1 // $Id: Process.cpp 82499 2008-08-04 20:01:17Z shuston $
3 #include "ace/Process.h"
5 #if !defined (__ACE_INLINE__)
6 #include "ace/Process.inl"
7 #endif /* __ACE_INLINE__ */
10 #include "ace/Auto_Ptr.h"
11 #include "ace/Signal.h"
12 #include "ace/SString.h"
13 #include "ace/Log_Msg.h"
14 #include "ace/OS_NS_stdio.h"
15 #include "ace/OS_NS_stdlib.h"
16 #include "ace/OS_NS_sys_socket.h"
17 #include "ace/OS_NS_errno.h"
18 #include "ace/OS_NS_string.h"
19 #include "ace/OS_NS_unistd.h"
20 #include "ace/OS_Memory.h"
21 #include "ace/Countdown_Time.h"
22 #include "ace/Truncate.h"
23 #include "ace/Vector_T.h"
25 #if defined (ACE_VXWORKS) && (ACE_VXWORKS > 0x600) && defined (__RTP__)
30 ACE_RCSID (ace
, Process
, "$Id: Process.cpp 82499 2008-08-04 20:01:17Z shuston $")
32 // This function acts as a signal handler for SIGCHLD. We don't really want
33 // to do anything with the signal - it's just needed to interrupt a sleep.
34 // See wait() for more info.
35 #if !defined (ACE_WIN32) && !defined(ACE_LACKS_UNIX_SIGNALS)
37 sigchld_nop (int, siginfo_t
*, ucontext_t
*)
41 #endif /* ACE_WIN32 */
44 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
46 ACE_Process::ACE_Process (void)
48 #if !defined (ACE_WIN32)
49 child_id_ (ACE_INVALID_PID
),
50 #endif /* !defined (ACE_WIN32) */
53 #if defined (ACE_WIN32)
54 ACE_OS::memset ((void *) &this->process_info_
,
56 sizeof this->process_info_
);
57 #endif /* ACE_WIN32 */
60 ACE_Process::~ACE_Process (void)
62 #if defined (ACE_WIN32)
63 // Free resources allocated in kernel.
64 ACE_OS::close (this->process_info_
.hThread
);
65 ACE_OS::close (this->process_info_
.hProcess
);
66 #endif /* ACE_WIN32 */
67 // If any handles were duplicated for the child process and
68 // still not closed, get them now.
69 this->close_dup_handles ();
73 ACE_Process::prepare (ACE_Process_Options
&)
79 ACE_Process::spawn (ACE_Process_Options
&options
)
81 if (this->prepare (options
) < 0)
82 return ACE_INVALID_PID
;
84 // Stash the passed/duped handle sets away in this object for later
85 // closing if needed or requested. At the same time, figure out which
86 // ones to include in command line options if that's needed below.
87 ACE_Handle_Set
*set_p
= 0;
88 if (options
.dup_handles (this->dup_handles_
))
89 set_p
= &this->dup_handles_
;
90 else if (options
.passed_handles (this->handles_passed_
))
91 set_p
= &this->handles_passed_
;
93 // If we are going to end up running a new program (i.e. Win32, or
94 // NO_EXEC option is set) then get any handles passed in the options,
95 // and tack them onto the command line with +H <handle> options,
96 // unless the command line runs out of space.
97 // Note that we're using the knowledge that all the options, argvs, etc.
98 // passed to the options are all sitting in the command_line_buf. Any
99 // call to get the argv then splits them out. So, regardless of the
100 // platform, tack them all onto the command line buf and take it
102 if (set_p
&& !ACE_BIT_ENABLED (options
.creation_flags (),
103 ACE_Process_Options::NO_EXEC
))
106 ACE_TCHAR
*cmd_line_buf
= options
.command_line_buf (&maxlen
);
107 size_t max_len
= static_cast<size_t> (maxlen
);
108 size_t curr_len
= ACE_OS::strlen (cmd_line_buf
);
109 ACE_Handle_Set_Iterator
h_iter (*set_p
);
110 // Because the length of the to-be-formatted +H option is not
111 // known, and we don't have a snprintf, guess at the space
112 // needed (20 chars), and use that as a limit.
113 for (ACE_HANDLE h
= h_iter ();
114 h
!= ACE_INVALID_HANDLE
&& curr_len
+ 20 < max_len
;
117 #if defined (ACE_WIN32)
118 # if defined (ACE_WIN64)
119 curr_len
+= ACE_OS::sprintf (&cmd_line_buf
[curr_len
],
120 ACE_TEXT (" +H %I64p"),
123 curr_len
+= ACE_OS::sprintf (&cmd_line_buf
[curr_len
],
126 # endif /* ACE_WIN64 */
128 curr_len
+= ACE_OS::sprintf (&cmd_line_buf
[curr_len
],
131 #endif /* ACE_WIN32 */
135 #if defined (ACE_HAS_WINCE)
136 // Note that WinCE does not have process name included in the command line as argv[0]
137 // like other OS environment. Therefore, it is user's whole responsibility to call
138 // 'ACE_Process_Options::process_name(const ACE_TCHAR *name)' to set the proper
139 // process name (the execution file name with path if needed).
142 ACE_TEXT_CreateProcess (options
.process_name(),
143 options
.command_line_buf(),
144 options
.get_process_attributes(), // must be NULL in CE
145 options
.get_thread_attributes(), // must be NULL in CE
146 options
.handle_inheritence(), // must be false in CE
147 options
.creation_flags(), // must be NULL in CE
148 options
.env_buf(), // environment variables, must be NULL in CE
149 options
.working_directory(), // must be NULL in CE
150 options
.startup_info(), // must be NULL in CE
151 &this->process_info_
);
155 parent (this->getpid ());
156 return this->getpid ();
158 return ACE_INVALID_PID
;
160 #elif defined (ACE_WIN32)
161 void* env_buf
= options
.env_buf ();
162 DWORD flags
= options
.creation_flags ();
163 # if defined (ACE_HAS_WCHAR) && !defined (ACE_USES_WCHAR)
164 wchar_t* wenv_buf
= 0;
165 if (options
.use_unicode_environment ())
167 wenv_buf
= this->convert_env_buffer (options
.env_buf ());
169 flags
|= CREATE_UNICODE_ENVIRONMENT
;
174 ACE_TEXT_CreateProcess (0,
175 options
.command_line_buf (),
176 options
.get_process_attributes (),
177 options
.get_thread_attributes (),
178 options
.handle_inheritence (),
180 env_buf
, // environment variables
181 options
.working_directory (),
182 options
.startup_info (),
183 &this->process_info_
);
185 # if defined (ACE_HAS_WCHAR) && !defined (ACE_USES_WCHAR)
186 if (options
.use_unicode_environment ())
192 parent (this->getpid ());
193 return this->getpid ();
195 return ACE_INVALID_PID
;
197 #elif defined(ACE_OPENVMS)
198 if (ACE_BIT_ENABLED (options
.creation_flags (),
199 ACE_Process_Options::NO_EXEC
))
200 ACE_NOTSUP_RETURN (ACE_INVALID_PID
);
202 int saved_stdin
= ACE_STDIN
;
203 int saved_stdout
= ACE_STDOUT
;
204 int saved_stderr
= ACE_STDERR
;
205 // Save STD file descriptors and redirect
206 if (options
.get_stdin () != ACE_INVALID_HANDLE
) {
207 if ((saved_stdin
= ACE_OS::dup (ACE_STDIN
)) == -1 && errno
!= EBADF
)
208 ACE_OS::exit (errno
);
209 if (ACE_OS::dup2 (options
.get_stdin (), ACE_STDIN
) == -1)
210 ACE_OS::exit (errno
);
212 if (options
.get_stdout () != ACE_INVALID_HANDLE
) {
213 if ((saved_stdout
= ACE_OS::dup (ACE_STDOUT
)) == -1 && errno
!= EBADF
)
214 ACE_OS::exit (errno
);
215 if (ACE_OS::dup2 (options
.get_stdout (), ACE_STDOUT
) == -1)
216 ACE_OS::exit (errno
);
218 if (options
.get_stderr () != ACE_INVALID_HANDLE
) {
219 if ((saved_stderr
= ACE_OS::dup (ACE_STDERR
)) == -1 && errno
!= EBADF
)
220 ACE_OS::exit (errno
);
221 if (ACE_OS::dup2 (options
.get_stderr (), ACE_STDERR
) == -1)
222 ACE_OS::exit (errno
);
225 if (options
.working_directory () != 0)
226 ACE_NOTSUP_RETURN (ACE_INVALID_PID
);
228 this->child_id_
= vfork();
229 if (this->child_id_
== 0) {
230 ACE_OS::execvp (options
.process_name (),
231 options
.command_line_argv ());
232 // something went wrong
233 this->child_id_
= ACE_INVALID_PID
;
236 // restore STD file descriptors (if necessary)
237 if (options
.get_stdin () != ACE_INVALID_HANDLE
) {
238 if (saved_stdin
== -1)
239 ACE_OS::close (ACE_STDIN
);
241 ACE_OS::dup2 (saved_stdin
, ACE_STDIN
);
243 if (options
.get_stdout () != ACE_INVALID_HANDLE
) {
244 if (saved_stdout
== -1)
245 ACE_OS::close (ACE_STDOUT
);
247 ACE_OS::dup2 (saved_stdout
, ACE_STDOUT
);
249 if (options
.get_stderr () != ACE_INVALID_HANDLE
) {
250 if (saved_stderr
== -1)
251 ACE_OS::close (ACE_STDERR
);
253 ACE_OS::dup2 (saved_stderr
, ACE_STDERR
);
256 return this->child_id_
;
257 #elif (defined (ACE_VXWORKS) && (ACE_VXWORKS > 0x600)) && defined (__RTP__)
258 if (ACE_BIT_ENABLED (options
.creation_flags (),
259 ACE_Process_Options::NO_EXEC
))
260 ACE_NOTSUP_RETURN (ACE_INVALID_PID
);
262 if (options
.working_directory () != 0)
263 ACE_NOTSUP_RETURN (ACE_INVALID_PID
);
265 int saved_stdin
= ACE_STDIN
;
266 int saved_stdout
= ACE_STDOUT
;
267 int saved_stderr
= ACE_STDERR
;
268 // Save STD file descriptors and redirect
269 if (options
.get_stdin () != ACE_INVALID_HANDLE
) {
270 if ((saved_stdin
= ACE_OS::dup (ACE_STDIN
)) == -1 && errno
!= EBADF
)
271 ACE_OS::exit (errno
);
272 if (ACE_OS::dup2 (options
.get_stdin (), ACE_STDIN
) == -1)
273 ACE_OS::exit (errno
);
275 if (options
.get_stdout () != ACE_INVALID_HANDLE
) {
276 if ((saved_stdout
= ACE_OS::dup (ACE_STDOUT
)) == -1 && errno
!= EBADF
)
277 ACE_OS::exit (errno
);
278 if (ACE_OS::dup2 (options
.get_stdout (), ACE_STDOUT
) == -1)
279 ACE_OS::exit (errno
);
281 if (options
.get_stderr () != ACE_INVALID_HANDLE
) {
282 if ((saved_stderr
= ACE_OS::dup (ACE_STDERR
)) == -1 && errno
!= EBADF
)
283 ACE_OS::exit (errno
);
284 if (ACE_OS::dup2 (options
.get_stderr (), ACE_STDERR
) == -1)
285 ACE_OS::exit (errno
);
288 // Wide-char builds need narrow-char strings for commandline and
289 // environment variables.
290 # if defined (ACE_USES_WCHAR)
291 wchar_t * const *wargv
= options
.command_line_argv ();
293 for (vcount
= 0; wargv
[vcount
] != 0; ++vcount
)
295 char **procargv
= new char *[vcount
+ 1]; // Need 0 at the end
296 procargv
[vcount
] = 0;
297 for (i
= 0; i
< vcount
; ++i
)
298 procargv
[i
] = ACE_Wide_To_Ascii::convert (wargv
[i
]);
301 if (options
.inherit_environment ())
303 wargv
= options
.env_argv ();
304 for (vcount
= 0; wargv
[vcount
] != 0; ++vcount
)
306 procenv
= new char *[vcount
+ 1]; // Need 0 at the end
308 for (i
= 0; i
< vcount
; ++i
)
309 procenv
[i
] = ACE_Wide_To_Ascii::convert (wargv
[i
]);
312 const char **procargv
= const_cast<const char**> (options
.command_line_argv ());
313 const char **procenv
= const_cast<const char**> (options
.env_argv ());
314 # endif /* ACE_USES_WCHAR */
316 this->child_id_
= ::rtpSpawn (procargv
[0],
320 0x10000, // uStackSize
322 VX_FP_TASK
); // taskOptions
323 int my_errno_
= errno
;
324 if (this->child_id_
== ERROR
) {
325 // something went wrong
326 this->child_id_
= ACE_INVALID_PID
;
329 # if defined (ACE_USES_WCHAR)
332 # endif /* ACE_USES_WCHAR */
334 // restore STD file descriptors (if necessary)
335 if (options
.get_stdin () != ACE_INVALID_HANDLE
) {
336 if (saved_stdin
== -1)
337 ACE_OS::close (ACE_STDIN
);
339 ACE_OS::dup2 (saved_stdin
, ACE_STDIN
);
341 if (options
.get_stdout () != ACE_INVALID_HANDLE
) {
342 if (saved_stdout
== -1)
343 ACE_OS::close (ACE_STDOUT
);
345 ACE_OS::dup2 (saved_stdout
, ACE_STDOUT
);
347 if (options
.get_stderr () != ACE_INVALID_HANDLE
) {
348 if (saved_stderr
== -1)
349 ACE_OS::close (ACE_STDERR
);
351 ACE_OS::dup2 (saved_stderr
, ACE_STDERR
);
354 if (this->child_id_
== ACE_INVALID_PID
)
359 return this->child_id_
;
360 #else /* ACE_WIN32 */
361 // Fork the new process.
362 this->child_id_
= ACE::fork (options
.process_name (),
363 options
.avoid_zombies ());
365 if (this->child_id_
== 0)
367 # if !defined (ACE_LACKS_SETPGID)
368 // If we're the child and the options specified a non-default
369 // process group, try to set our pgid to it. This allows the
370 // <ACE_Process_Manager> to wait for processes by their
372 if (options
.getgroup () != ACE_INVALID_PID
373 && ACE_OS::setpgid (0,
374 options
.getgroup ()) < 0)
376 #if !defined (ACE_HAS_THREADS)
377 // We can't emit this log message because ACE_ERROR(), etc.
378 // will invoke async signal unsafe functions, which results
379 // in undefined behavior in threaded programs.
380 ACE_ERROR ((LM_ERROR
,
382 ACE_TEXT ("ACE_Process::spawn: setpgid failed.")));
385 # endif /* ACE_LACKS_SETPGID */
387 # if !defined (ACE_LACKS_SETREGID)
388 if (options
.getrgid () != (uid_t
) -1
389 || options
.getegid () != (uid_t
) -1)
390 if (ACE_OS::setregid (options
.getrgid (),
391 options
.getegid ()) == -1)
393 #if !defined (ACE_HAS_THREADS)
394 // We can't emit this log message because ACE_ERROR(), etc.
395 // will invoke async signal unsafe functions, which results
396 // in undefined behavior in threaded programs.
397 ACE_ERROR ((LM_ERROR
,
399 ACE_TEXT ("ACE_Process::spawn: setregid failed.")));
402 # endif /* ACE_LACKS_SETREGID */
404 # if !defined (ACE_LACKS_SETREUID)
405 // Set user and group id's.
406 if (options
.getruid () != (uid_t
) -1
407 || options
.geteuid () != (uid_t
) -1)
408 if (ACE_OS::setreuid (options
.getruid (),
409 options
.geteuid ()) == -1)
411 #if !defined (ACE_HAS_THREADS)
412 // We can't emit this log message because ACE_ERROR(), etc.
413 // will invoke async signal unsafe functions, which results
414 // in undefined behavior in threaded programs.
415 ACE_ERROR ((LM_ERROR
,
417 ACE_TEXT ("ACE_Process::spawn: setreuid failed.")));
420 # endif /* ACE_LACKS_SETREUID */
422 this->child (ACE_OS::getppid ());
424 else if (this->child_id_
!= -1)
425 this->parent (this->child_id_
);
427 // If we're not supposed to exec, return the process id.
428 if (ACE_BIT_ENABLED (options
.creation_flags (),
429 ACE_Process_Options::NO_EXEC
))
430 return this->child_id_
;
432 switch (this->child_id_
)
436 return ACE_INVALID_PID
;
438 // Child process...exec the
440 if (options
.get_stdin () != ACE_INVALID_HANDLE
441 && ACE_OS::dup2 (options
.get_stdin (),
443 ACE_OS::exit (errno
);
444 else if (options
.get_stdout () != ACE_INVALID_HANDLE
445 && ACE_OS::dup2 (options
.get_stdout (),
447 ACE_OS::exit (errno
);
448 else if (options
.get_stderr () != ACE_INVALID_HANDLE
449 && ACE_OS::dup2 (options
.get_stderr (),
451 ACE_OS::exit (errno
);
453 // close down unneeded descriptors
454 ACE_OS::close (options
.get_stdin ());
455 ACE_OS::close (options
.get_stdout ());
456 ACE_OS::close (options
.get_stderr ());
458 // If we must, set the working directory for the child
460 if (options
.working_directory () != 0)
461 ACE_OS::chdir (options
.working_directory ());
462 // Should check for error here!
464 // Child process executes the command.
467 // Wide-char builds not on Windows need narrow-char strings for
468 // exec() and environment variables. Don't need to worry about
469 // releasing any of the converted string memory since this
470 // process will either exec() or exit() shortly.
471 # if defined (ACE_USES_WCHAR)
472 ACE_Wide_To_Ascii
n_procname (options
.process_name ());
473 const char *procname
= n_procname
.char_rep ();
475 wchar_t * const *wargv
= options
.command_line_argv ();
477 for (vcount
= 0; wargv
[vcount
] != 0; ++vcount
)
479 char **procargv
= new char *[vcount
+ 1]; // Need 0 at the end
480 procargv
[vcount
] = 0;
481 for (i
= 0; i
< vcount
; ++i
)
482 procargv
[i
] = ACE_Wide_To_Ascii::convert (wargv
[i
]);
484 wargv
= options
.env_argv ();
485 for (vcount
= 0; wargv
[vcount
] != 0; ++vcount
)
487 char **procenv
= new char *[vcount
+ 1]; // Need 0 at the end
489 for (i
= 0; i
< vcount
; ++i
)
490 procenv
[i
] = ACE_Wide_To_Ascii::convert (wargv
[i
]);
492 const char *procname
= options
.process_name ();
493 char *const *procargv
= options
.command_line_argv ();
494 char *const *procenv
= options
.env_argv ();
495 # endif /* ACE_USES_WCHAR */
497 if (options
.inherit_environment ())
499 // Add the new environment variables to the environment
500 // context of the context before doing an <execvp>.
501 for (size_t i
= 0; procenv
[i
] != 0; i
++)
502 if (ACE_OS::putenv (procenv
[i
]) != 0)
503 return ACE_INVALID_PID
;
505 // Now the forked process has both inherited variables and
506 // the user's supplied variables.
507 result
= ACE_OS::execvp (procname
, procargv
);
512 // GreenHills 1.8.8 (for VxWorks 5.3.x) can't compile this
513 // code. Processes aren't supported on VxWorks anyways.
514 ACE_NOTSUP_RETURN (ACE_INVALID_PID
);
516 result
= ACE_OS::execve (procname
, procargv
, procenv
);
521 // If the execv fails, this child needs to exit.
523 // Exit with the errno so that the calling process can
524 // catch this and figure out what went wrong.
525 ACE_OS::_exit (errno
);
527 // ... otherwise, this is never reached.
531 // Server process. The fork succeeded.
532 return this->child_id_
;
534 #endif /* ACE_WIN32 */
538 ACE_Process::parent (pid_t
)
544 ACE_Process::child (pid_t
)
550 ACE_Process::unmanage (void)
556 ACE_Process::running (void) const
558 #if defined (ACE_WIN32)
561 BOOL result
= ::GetExitCodeProcess (this->gethandle (),
563 return result
&& code
== STILL_ACTIVE
;
565 if (ACE_INVALID_PID
== this->getpid ())
568 return ACE_OS::kill (this->getpid (),
571 #endif /* ACE_WIN32 */
575 ACE_Process::wait (const ACE_Time_Value
&tv
,
576 ACE_exitcode
*status
)
578 #if defined (ACE_WIN32)
579 // Don't try to get the process exit status if wait failed so we can
580 // keep the original error code intact.
581 switch (::WaitForSingleObject (process_info_
.hProcess
,
585 // The error status of <GetExitCodeProcess> is nonetheless not
586 // tested because we don't know how to return the value.
587 ::GetExitCodeProcess (process_info_
.hProcess
,
590 *status
= this->exit_code_
;
591 return this->getpid ();
596 ACE_OS::set_errno_to_last_error ();
599 #elif defined(ACE_LACKS_UNIX_SIGNALS)
600 if (tv
== ACE_Time_Value::zero
)
603 ACE_OS::waitpid (this->child_id_
,
607 *status
= this->exit_code_
;
612 if (tv
== ACE_Time_Value::max_time
)
613 # if defined (ACE_VXWORKS)
616 while ( (retv
= this->wait (status
)) == ACE_INVALID_PID
&& errno
== EINTR
) ;
620 return this->wait (status
);
624 ACE_Time_Value
sleeptm (1); // 1 msec
625 if (sleeptm
> tv
) // if sleeptime > waittime
627 ACE_Time_Value
tmo (tv
); // Need one we can change
628 for (ACE_Countdown_Time
time_left (&tmo
); tmo
> ACE_Time_Value::zero
; time_left
.update ())
630 pid
= ACE_OS::waitpid (this->getpid (),
634 *status
= this->exit_code_
;
636 if (pid
> 0 || pid
== ACE_INVALID_PID
)
637 break; // Got a child or an error - all done
639 // pid 0, nothing is ready yet, so wait.
640 // Do a (very) short sleep (only this thread sleeps).
641 ACE_OS::sleep (sleeptm
);
645 #else /* !ACE_WIN32 && !ACE_LACKS_UNIX_SIGNALS */
646 if (tv
== ACE_Time_Value::zero
)
649 ACE_OS::waitpid (this->child_id_
,
653 *status
= this->exit_code_
;
658 if (tv
== ACE_Time_Value::max_time
)
659 return this->wait (status
);
661 // Need to wait but limited to specified time.
662 // Force generation of SIGCHLD, even though we don't want to
663 // catch it - just need it to interrupt the sleep below.
664 // If this object has a reactor set, assume it was given at
665 // open(), and there's already a SIGCHLD action set, so no
666 // action is needed here.
667 ACE_Sig_Action old_action
;
668 ACE_Sig_Action
do_sigchld ((ACE_SignalHandler
)sigchld_nop
);
669 do_sigchld
.register_action (SIGCHLD
, &old_action
);
672 ACE_Time_Value
tmo (tv
); // Need one we can change
673 for (ACE_Countdown_Time
time_left (&tmo
); ; time_left
.update ())
675 pid
= ACE_OS::waitpid (this->getpid (),
679 *status
= this->exit_code_
;
681 if (pid
> 0 || pid
== ACE_INVALID_PID
)
682 break; // Got a child or an error - all done
684 // pid 0, nothing is ready yet, so wait.
685 // Do a sleep (only this thread sleeps) til something
686 // happens. This relies on SIGCHLD interrupting the sleep.
687 // If SIGCHLD isn't delivered, we'll need to do something
688 // with sigaction to force it.
689 if (-1 == ACE_OS::sleep (tmo
) && errno
== EINTR
)
696 // Restore the previous SIGCHLD action if it was changed.
697 old_action
.register_action (SIGCHLD
);
700 #endif /* ACE_WIN32 */
704 ACE_Process::close_dup_handles (void)
706 if (this->dup_handles_
.num_set () > 0)
708 ACE_Handle_Set_Iterator
h_iter (this->dup_handles_
);
709 for (ACE_HANDLE h
= h_iter ();
710 h
!= ACE_INVALID_HANDLE
;
712 ACE_OS::closesocket (h
);
713 this->dup_handles_
.reset ();
719 ACE_Process::close_passed_handles (void)
721 if (this->handles_passed_
.num_set () > 0)
723 ACE_Handle_Set_Iterator
h_iter (this->handles_passed_
);
724 for (ACE_HANDLE h
= h_iter ();
725 h
!= ACE_INVALID_HANDLE
;
727 ACE_OS::closesocket (h
);
728 this->handles_passed_
.reset ();
733 #if defined (ACE_WIN32) && \
734 defined (ACE_HAS_WCHAR) && !defined (ACE_USES_WCHAR) && \
735 !defined (ACE_HAS_WINCE)
737 ACE_Process::convert_env_buffer (const char* env
) const
739 // Total starts out at 1 due to the final block nul terminator
742 // Convert each individual character string to the equivalent wide
744 ACE_Vector
<wchar_t*> buffer
;
751 // Convert the char string to wchar_t
752 wchar_t* str
= ACE_Ascii_To_Wide::convert (env
+ start
);
754 // Add the length of the string plus the nul terminator
755 total
+= ACE_OS::strlen (str
) + 1;
757 // Save it and set up for the next string
758 buffer
.push_back (str
);
760 if (env
[start
] == '\0')
765 i
+= ACE_OS::strlen (env
+ i
);
769 // Copy each string into the buffer leaving a nul terminator between
770 // each string and adding a second nul terminator at the end
772 wchar_t* wenv
= new wchar_t[total
];
773 size_t length
= buffer
.size ();
774 for (i
= 0; i
< length
; ++i
)
776 ACE_OS::strcpy(wenv
+ start
, buffer
[i
]);
777 start
+= ACE_OS::strlen (buffer
[i
]) + 1;
785 ACE_Process_Options::ACE_Process_Options (bool inherit_environment
,
786 int command_line_buf_len
,
790 #if !defined (ACE_HAS_WINCE)
791 inherit_environment_ (inherit_environment
),
792 #endif /* ACE_HAS_WINCE */
795 #if !defined (ACE_HAS_WINCE)
796 #if defined (ACE_WIN32)
797 environment_inherited_ (0),
798 handle_inheritence_ (TRUE
),
799 process_attributes_ (0),
800 thread_attributes_ (0),
801 #else /* ACE_WIN32 */
802 stdin_ (ACE_INVALID_HANDLE
),
803 stdout_ (ACE_INVALID_HANDLE
),
804 stderr_ (ACE_INVALID_HANDLE
),
809 #endif /* ACE_WIN32 */
810 set_handles_called_ (0),
811 environment_buf_index_ (0),
812 environment_argv_index_ (0),
813 environment_buf_ (0),
814 environment_buf_len_ (env_buf_len
),
815 max_environment_args_ (max_env_args
),
816 max_environ_argv_index_ (max_env_args
- 1),
817 #endif /* !ACE_HAS_WINCE */
818 command_line_argv_calculated_ (0),
819 command_line_buf_ (0),
820 command_line_copy_ (0),
821 command_line_buf_len_ (command_line_buf_len
),
822 process_group_ (ACE_INVALID_PID
),
823 use_unicode_environment_ (false)
825 ACE_NEW (command_line_buf_
,
826 ACE_TCHAR
[command_line_buf_len
]);
827 command_line_buf_
[0] = '\0';
829 #if !defined (ACE_HAS_WINCE)
830 working_directory_
[0] = '\0';
831 ACE_NEW (environment_buf_
,
832 ACE_TCHAR
[env_buf_len
]);
833 ACE_NEW (environment_argv_
,
834 ACE_TCHAR
*[max_env_args
]);
835 environment_buf_
[0] = '\0';
836 environment_argv_
[0] = 0;
837 process_name_
[0] = '\0';
838 #if defined (ACE_WIN32)
839 ACE_OS::memset ((void *) &this->startup_info_
,
841 sizeof this->startup_info_
);
842 this->startup_info_
.cb
= sizeof this->startup_info_
;
843 #endif /* ACE_WIN32 */
844 #endif /* !ACE_HAS_WINCE */
847 #if !defined (ACE_HAS_WINCE)
848 #if defined (ACE_WIN32)
850 ACE_Process_Options::inherit_environment (void)
852 // Ensure only once execution.
853 if (environment_inherited_
)
855 environment_inherited_
= 1;
857 // Get the existing environment.
858 ACE_TCHAR
*existing_environment
= 0;
859 #if defined (ACE_HAS_WCHAR) && !defined (ACE_USES_WCHAR)
860 WCHAR
*existing_wide_env
= 0;
861 ACE_Vector
<char> temp_narrow_env
;
862 if (this->use_unicode_environment_
)
864 existing_wide_env
= ::GetEnvironmentStringsW ();
865 for (WCHAR
*iter
= existing_wide_env
; *iter
; ++iter
)
867 ACE_Wide_To_Ascii
wta (iter
);
868 size_t len
= ACE_OS::strlen (wta
.char_rep ());
869 size_t idx
= temp_narrow_env
.size ();
870 temp_narrow_env
.resize (idx
+ len
+ 1, 0);
871 ACE_OS::strncpy (&temp_narrow_env
[idx
], wta
.char_rep (), len
);
874 temp_narrow_env
.push_back (0);
875 existing_environment
= &temp_narrow_env
[0];
879 existing_environment
= ACE_OS::getenvstrings ();
883 while (existing_environment
[slot
] != '\0')
885 size_t len
= ACE_OS::strlen (existing_environment
+ slot
);
887 // Add the string to our env buffer.
888 if (this->setenv_i (existing_environment
+ slot
, len
) == -1)
890 ACE_ERROR ((LM_ERROR
,
892 ACE_TEXT ("ACE_Process_Options::ACE_Process_Options")));
896 // Skip to the next word.
900 #if defined (ACE_HAS_WCHAR) && !defined (ACE_USES_WCHAR)
901 if (this->use_unicode_environment_
)
902 ::FreeEnvironmentStringsW (existing_wide_env
);
905 ACE_TEXT_FreeEnvironmentStrings (existing_environment
);
908 #else /* defined ACE_WIN32 */
911 ACE_Process_Options::env_argv (void)
913 return environment_argv_
;
916 #endif /* ACE_WIN32 */
919 ACE_Process_Options::enable_unicode_environment (void)
921 this->use_unicode_environment_
= true;
925 ACE_Process_Options::disable_unicode_environment (void)
927 this->use_unicode_environment_
= false;
931 ACE_Process_Options::use_unicode_environment (void) const
933 return this->use_unicode_environment_
;
937 ACE_Process_Options::setenv (ACE_TCHAR
*envp
[])
942 if (this->setenv_i (envp
[i
],
943 ACE_OS::strlen (envp
[i
])) == -1)
948 #if defined (ACE_WIN32)
949 if (inherit_environment_
)
950 this->inherit_environment ();
951 #endif /* ACE_WIN32 */
957 ACE_Process_Options::setenv (const ACE_TCHAR
*format
, ...)
959 ACE_TCHAR stack_buf
[DEFAULT_COMMAND_LINE_BUF_LEN
];
963 va_start (argp
, format
);
965 // Add the rest of the varargs.
966 ACE_OS::vsprintf (stack_buf
,
972 // Append the string to are environment buffer.
973 if (this->setenv_i (stack_buf
,
974 ACE_OS::strlen (stack_buf
)) == -1)
977 #if defined (ACE_WIN32)
978 if (inherit_environment_
)
979 this->inherit_environment ();
980 #endif /* ACE_WIN32 */
986 ACE_Process_Options::setenv (const ACE_TCHAR
*variable_name
,
987 const ACE_TCHAR
*format
, ...)
989 // To address the potential buffer overflow,
990 // we now allocate the buffer on heap with a variable size.
991 size_t const buflen
= ACE_OS::strlen (variable_name
) + ACE_OS::strlen (format
) + 2;
992 ACE_TCHAR
*newformat
= 0;
993 ACE_NEW_RETURN (newformat
, ACE_TCHAR
[buflen
], -1);
994 ACE_Auto_Basic_Array_Ptr
<ACE_TCHAR
> safe_newformat (newformat
);
996 // Add in the variable name.
997 ACE_OS::sprintf (safe_newformat
.get (),
1004 va_start (argp
, format
);
1006 // Add the rest of the varargs.
1007 size_t tmp_buflen
= DEFAULT_COMMAND_LINE_BUF_LEN
> buflen
1008 ? static_cast<size_t> (DEFAULT_COMMAND_LINE_BUF_LEN
) : buflen
;
1011 ACE_TCHAR
*stack_buf
= 0;
1012 ACE_NEW_RETURN (stack_buf
, ACE_TCHAR
[tmp_buflen
], -1);
1013 ACE_Auto_Basic_Array_Ptr
<ACE_TCHAR
> safe_stack_buf (stack_buf
);
1017 retval
= ACE_OS::vsnprintf (safe_stack_buf
.get (), tmp_buflen
, safe_newformat
.get (), argp
);
1018 if (retval
> ACE_Utils::truncate_cast
<int> (tmp_buflen
))
1021 ACE_NEW_RETURN (stack_buf
, ACE_TCHAR
[tmp_buflen
], -1);
1022 safe_stack_buf
.reset (stack_buf
);
1031 // In case that vsnprintf is not supported,
1032 // e.g., LynxOS and VxWorks 5, we have to
1033 // fall back to vsprintf.
1034 if (errno
== ENOTSUP
)
1036 // ALERT: Since we have to use vsprintf here, there is still a chance that
1037 // the stack_buf overflows, i.e., the length of the resulting string
1038 // can still possibly go beyond the allocated stack_buf.
1039 retval
= ACE_OS::vsprintf (safe_stack_buf
.get (), safe_newformat
.get (), argp
);
1041 // vsprintf is failed.
1045 // vsnprintf is failed.
1052 // Append the string to our environment buffer.
1053 if (this->setenv_i (safe_stack_buf
.get (),
1054 ACE_OS::strlen (safe_stack_buf
.get ())) == -1)
1057 #if defined (ACE_WIN32)
1058 if (inherit_environment_
)
1059 this->inherit_environment ();
1060 #endif /* ACE_WIN32 */
1066 ACE_Process_Options::setenv_i (ACE_TCHAR
*assignment
,
1069 // Add one for the null char.
1072 // If environment larger than allocated buffer return. Also check to
1073 // make sure we have enough room.
1074 if (environment_argv_index_
== max_environ_argv_index_
1075 || (len
+ environment_buf_index_
) >= environment_buf_len_
)
1078 // Copy the new environment string.
1079 ACE_OS::memcpy (environment_buf_
+ environment_buf_index_
,
1081 len
* sizeof (ACE_TCHAR
));
1083 // Update the argv array.
1084 environment_argv_
[environment_argv_index_
++] =
1085 environment_buf_
+ environment_buf_index_
;
1086 environment_argv_
[environment_argv_index_
] = 0;
1088 // Update our index.
1089 environment_buf_index_
+= len
;
1091 // Make sure the buffer is null-terminated.
1092 environment_buf_
[environment_buf_index_
] = '\0';
1097 ACE_Process_Options::set_handles (ACE_HANDLE std_in
,
1101 this->set_handles_called_
= 1;
1102 #if defined (ACE_WIN32)
1104 // Tell the new process to use our std handles.
1105 this->startup_info_
.dwFlags
= STARTF_USESTDHANDLES
;
1107 if (std_in
== ACE_INVALID_HANDLE
)
1109 if (std_out
== ACE_INVALID_HANDLE
)
1110 std_out
= ACE_STDOUT
;
1111 if (std_err
== ACE_INVALID_HANDLE
)
1112 std_err
= ACE_STDERR
;
1114 if (!::DuplicateHandle (::GetCurrentProcess (),
1116 ::GetCurrentProcess (),
1117 &this->startup_info_
.hStdInput
,
1120 DUPLICATE_SAME_ACCESS
))
1123 if (!::DuplicateHandle (::GetCurrentProcess (),
1125 ::GetCurrentProcess (),
1126 &this->startup_info_
.hStdOutput
,
1129 DUPLICATE_SAME_ACCESS
))
1132 if (!::DuplicateHandle (::GetCurrentProcess (),
1134 ::GetCurrentProcess (),
1135 &this->startup_info_
.hStdError
,
1138 DUPLICATE_SAME_ACCESS
))
1140 #else /* ACE_WIN32 */
1141 this->stdin_
= ACE_OS::dup (std_in
);
1142 this->stdout_
= ACE_OS::dup (std_out
);
1143 this->stderr_
= ACE_OS::dup (std_err
);
1144 #endif /* ACE_WIN32 */
1146 return 0; // Success.
1151 ACE_Process_Options::release_handles ()
1153 if (set_handles_called_
)
1155 #if defined (ACE_WIN32)
1156 ACE_OS::close (startup_info_
.hStdInput
);
1157 ACE_OS::close (startup_info_
.hStdOutput
);
1158 ACE_OS::close (startup_info_
.hStdError
);
1159 #else /* ACE_WIN32 */
1160 ACE_OS::close (stdin_
);
1161 ACE_OS::close (stdout_
);
1162 ACE_OS::close (stderr_
);
1163 #endif /* ACE_WIN32 */
1164 set_handles_called_
= 0;
1167 #endif /* !ACE_HAS_WINCE */
1170 ACE_Process_Options::~ACE_Process_Options (void)
1172 #if !defined (ACE_HAS_WINCE)
1174 delete [] environment_buf_
;
1175 delete [] environment_argv_
;
1176 #endif /* !ACE_HAS_WINCE */
1177 delete [] command_line_buf_
;
1178 ACE::strdelete (command_line_copy_
);
1182 ACE_Process_Options::command_line (const ACE_TCHAR
*const argv
[])
1184 // @@ Factor out the code between this
1189 ACE_OS::strcat (command_line_buf_
, argv
[i
]);
1192 ACE_OS::strcat (command_line_buf_
,
1194 ACE_OS::strcat (command_line_buf_
,
1199 command_line_argv_calculated_
= 0;
1200 return 0; // Success.
1204 ACE_Process_Options::command_line (const ACE_TCHAR
*format
, ...)
1206 // Store all ... args in argp.
1208 va_start (argp
, format
);
1210 if (command_line_buf_len_
< 1)
1213 #if !defined (ACE_LACKS_VSNPRINTF) || defined (ACE_HAS_TRIO)
1214 // vsnprintf the format and args into command_line_buf__.
1215 ACE_OS::vsnprintf (command_line_buf_
,
1216 command_line_buf_len_
,
1220 // sprintf the format and args into command_line_buf__.
1221 ACE_OS::vsprintf (command_line_buf_
,
1229 command_line_argv_calculated_
= 0;
1233 #if defined (ACE_HAS_WCHAR) && !defined (ACE_HAS_WINCE)
1235 * @note Not available on Windows CE because it doesn't have a char version of
1239 ACE_Process_Options::command_line (const ACE_ANTI_TCHAR
*format
, ...)
1241 ACE_ANTI_TCHAR
*anti_clb
;
1242 ACE_NEW_RETURN (anti_clb
,
1243 ACE_ANTI_TCHAR
[this->command_line_buf_len_
],
1246 // Store all ... args in argp.
1248 va_start (argp
, format
);
1250 // sprintf the format and args into command_line_buf_.
1251 ACE_OS::vsprintf (anti_clb
,
1258 ACE_OS::strcpy (this->command_line_buf_
,
1259 ACE_TEXT_ANTI_TO_TCHAR (anti_clb
));
1263 command_line_argv_calculated_
= 0;
1266 #endif /* ACE_HAS_WCHAR && !ACE_HAS_WINCE */
1269 ACE_Process_Options::env_buf (void)
1271 #if !defined (ACE_HAS_WINCE)
1272 if (environment_buf_
[0] == '\0')
1275 return environment_buf_
;
1278 #endif /* !ACE_HAS_WINCE */
1282 ACE_Process_Options::command_line_argv (void)
1284 if (command_line_argv_calculated_
== 0)
1286 command_line_argv_calculated_
= 1;
1288 // We need to free up any previous allocated memory first.
1289 ACE::strdelete (command_line_copy_
);
1291 // We need to make a dynamically allocated copy here since
1292 // ACE_Tokenizer modifies its arguments.
1293 command_line_copy_
= ACE::strnew (command_line_buf_
);
1294 // This tokenizer will replace all spaces with end-of-string
1295 // characters and will preserve text between "" and '' pairs.
1296 ACE_Tokenizer
parser (command_line_copy_
);
1297 parser
.delimiter_replace (' ', '\0');
1298 parser
.preserve_designators ('\"', '\"'); // "
1299 parser
.preserve_designators ('\'', '\'');
1303 command_line_argv_
[x
] = parser
.next ();
1304 while (command_line_argv_
[x
] != 0
1305 // substract one for the ending zero.
1306 && ++x
< MAX_COMMAND_LINE_OPTIONS
- 1);
1308 command_line_argv_
[x
] = 0;
1311 return command_line_argv_
;
1314 // Cause the specified handle to be passed to a child process
1315 // when it's spawned.
1317 ACE_Process_Options::pass_handle (ACE_HANDLE h
)
1319 # if defined (ACE_WIN32)
1320 # if defined (ACE_HAS_WINCE)
1321 ACE_NOTSUP_RETURN (-1);
1324 // This is oriented towards socket handles... may need some adjustment
1326 // This is all based on an MSDN article:
1327 // http://support.microsoft.com/support/kb/articles/Q150/5/23.asp
1328 // If on Win95/98, the handle needs to be duplicated for the to-be-spawned
1329 // process. On WinNT, they get inherited by the child process automatically.
1330 // If the handle is duplicated, remember the duplicate so it can be
1331 // closed later. Can't be closed now, or the child won't get it.
1332 ACE_TEXT_OSVERSIONINFO osvi
;
1333 ZeroMemory (&osvi
, sizeof (osvi
));
1334 osvi
.dwOSVersionInfoSize
= sizeof (ACE_TEXT_OSVERSIONINFO
);
1335 // If this is Win95/98 or we can't tell, duplicate the handle.
1336 if (!ACE_TEXT_GetVersionEx (&osvi
) || osvi
.dwPlatformId
!= VER_PLATFORM_WIN32_NT
)
1339 if (!DuplicateHandle (GetCurrentProcess (),
1340 static_cast<HANDLE
> (h
),
1341 GetCurrentProcess (),
1344 TRUE
, // Inheritable
1345 DUPLICATE_SAME_ACCESS
))
1347 dup_handles_
.set_bit (static_cast<ACE_HANDLE
> (dup_handle
));
1349 # endif /* ACE_HAS_WINCE */
1350 #endif /* ACE_WIN32 */
1352 this->handles_passed_
.set_bit (h
);
1357 // Get a copy of the handles the ACE_Process_Options duplicated
1358 // for the spawned process.
1360 ACE_Process_Options::dup_handles (ACE_Handle_Set
&set
) const
1362 if (this->dup_handles_
.num_set () == 0)
1365 set
= this->dup_handles_
;
1369 // Get a copy of the handles passed to the spawned process. This
1370 // will be the set of handles previously passed to @arg pass_handle().
1372 ACE_Process_Options::passed_handles (ACE_Handle_Set
&set
) const
1374 if (this->handles_passed_
.num_set () == 0)
1377 set
= this->handles_passed_
;
1381 ACE_Managed_Process::~ACE_Managed_Process (void)
1386 ACE_Managed_Process::unmanage (void)
1391 ACE_END_VERSIONED_NAMESPACE_DECL