1 #include "ace/Process.h"
3 #if !defined (__ACE_INLINE__)
4 #include "ace/Process.inl"
5 #endif /* __ACE_INLINE__ */
8 #include "ace/Auto_Ptr.h"
9 #include "ace/Signal.h"
10 #include "ace/SString.h"
11 #include "ace/Log_Category.h"
12 #include "ace/OS_NS_stdio.h"
13 #include "ace/OS_NS_stdlib.h"
14 #include "ace/OS_NS_sys_socket.h"
15 #include "ace/OS_NS_errno.h"
16 #include "ace/OS_NS_string.h"
17 #include "ace/OS_NS_unistd.h"
18 #include "ace/OS_NS_fcntl.h"
19 #include "ace/OS_Memory.h"
20 #include "ace/Countdown_Time.h"
21 #include "ace/Truncate.h"
22 #include "ace/Vector_T.h"
23 #include "ace/Tokenizer_T.h"
25 #if defined (ACE_VXWORKS) && defined (__RTP__)
30 // This function acts as a signal handler for SIGCHLD. We don't really want
31 // to do anything with the signal - it's just needed to interrupt a sleep.
32 // See wait() for more info.
33 #if !defined (ACE_WIN32) && !defined(ACE_LACKS_UNIX_SIGNALS)
35 sigchld_nop (int, siginfo_t
*, ucontext_t
*)
39 #endif /* ACE_WIN32 */
42 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
44 ACE_Process::ACE_Process (void)
46 #if !defined (ACE_WIN32)
47 child_id_ (ACE_INVALID_PID
),
48 #endif /* !defined (ACE_WIN32) */
51 #if defined (ACE_WIN32)
52 ACE_OS::memset ((void *) &this->process_info_
,
54 sizeof this->process_info_
);
55 #endif /* ACE_WIN32 */
58 ACE_Process::~ACE_Process (void)
60 #if defined (ACE_WIN32)
61 // Free resources allocated in kernel.
62 ACE_OS::close (this->process_info_
.hThread
);
63 ACE_OS::close (this->process_info_
.hProcess
);
64 #endif /* ACE_WIN32 */
65 // If any handles were duplicated for the child process and
66 // still not closed, get them now.
67 this->close_dup_handles ();
71 ACE_Process::prepare (ACE_Process_Options
&)
77 ACE_Process::spawn (ACE_Process_Options
&options
)
79 if (this->prepare (options
) < 0)
80 return ACE_INVALID_PID
;
82 // Stash the passed/duped handle sets away in this object for later
83 // closing if needed or requested. At the same time, figure out which
84 // ones to include in command line options if that's needed below.
85 ACE_Handle_Set
*set_p
= 0;
86 if (options
.dup_handles (this->dup_handles_
))
87 set_p
= &this->dup_handles_
;
88 else if (options
.passed_handles (this->handles_passed_
))
89 set_p
= &this->handles_passed_
;
91 // If we are going to end up running a new program (i.e. Win32, or
92 // NO_EXEC option is set) then get any handles passed in the options,
93 // and tack them onto the command line with +H <handle> options,
94 // unless the command line runs out of space.
95 // Note that we're using the knowledge that all the options, argvs, etc.
96 // passed to the options are all sitting in the command_line_buf. Any
97 // call to get the argv then splits them out. So, regardless of the
98 // platform, tack them all onto the command line buf and take it
100 if (set_p
&& !ACE_BIT_ENABLED (options
.creation_flags (),
101 ACE_Process_Options::NO_EXEC
))
104 ACE_TCHAR
*cmd_line_buf
= options
.command_line_buf (&max_len
);
105 size_t curr_len
= ACE_OS::strlen (cmd_line_buf
);
106 ACE_Handle_Set_Iterator
h_iter (*set_p
);
107 // Because the length of the to-be-formatted +H option is not
108 // known, and we don't have a snprintf, guess at the space
109 // needed (20 chars), and use that as a limit.
110 for (ACE_HANDLE h
= h_iter ();
111 h
!= ACE_INVALID_HANDLE
&& curr_len
+ 20 < max_len
;
114 #if defined (ACE_WIN32)
115 # if defined (ACE_WIN64)
116 // silence warnings coming from MinGW64 compilers
117 # if defined (__GNUC__)
118 # pragma GCC diagnostic push
119 # pragma GCC diagnostic ignored "-Wformat"
120 # pragma GCC diagnostic ignored "-Wformat-extra-args"
121 # endif /* __GNUC__ */
122 curr_len
+= ACE_OS::sprintf (&cmd_line_buf
[curr_len
],
123 ACE_TEXT (" +H %I64p"),
125 # if defined (__GNUC__)
126 # pragma GCC diagnostic pop
127 # endif /* __GNUC__ */
129 curr_len
+= ACE_OS::sprintf (&cmd_line_buf
[curr_len
],
132 # endif /* ACE_WIN64 */
134 curr_len
+= ACE_OS::sprintf (&cmd_line_buf
[curr_len
],
137 #endif /* ACE_WIN32 */
141 #if defined (ACE_HAS_WINCE)
142 // Note that WinCE does not have process name included in the command line as argv[0]
143 // like other OS environment. Therefore, it is user's whole responsibility to call
144 // 'ACE_Process_Options::process_name(const ACE_TCHAR *name)' to set the proper
145 // process name (the execution file name with path if needed).
147 ACE_TEXT_CreateProcess (options
.process_name(),
148 options
.command_line_buf(),
149 options
.get_process_attributes(), // must be NULL in CE
150 options
.get_thread_attributes(), // must be NULL in CE
151 options
.handle_inheritance(), // must be false in CE
152 options
.creation_flags(), // must be NULL in CE
153 options
.env_buf(), // environment variables, must be NULL in CE
154 options
.working_directory(), // must be NULL in CE
155 options
.startup_info(), // must be NULL in CE
156 &this->process_info_
);
160 parent (this->getpid ());
161 return this->getpid ();
163 return ACE_INVALID_PID
;
165 #elif defined (ACE_WIN32)
166 void* env_buf
= options
.env_buf ();
167 DWORD flags
= options
.creation_flags ();
168 # if defined (ACE_HAS_WCHAR) && !defined (ACE_USES_WCHAR)
169 wchar_t* wenv_buf
= 0;
170 if (options
.use_unicode_environment ())
172 wenv_buf
= this->convert_env_buffer (options
.env_buf ());
174 flags
|= CREATE_UNICODE_ENVIRONMENT
;
179 if (options
.get_user_token () == ACE_INVALID_HANDLE
)
181 fork_result
= ACE_TEXT_CreateProcess (0,
182 options
.command_line_buf (),
183 options
.get_process_attributes (),
184 options
.get_thread_attributes (),
185 options
.handle_inheritance (),
187 env_buf
, // environment variables
188 options
.working_directory (),
189 options
.startup_info (),
190 &this->process_info_
);
194 fork_result
= ACE_TEXT_CreateProcessAsUser (options
.get_user_token (),
196 options
.command_line_buf (),
197 options
.get_process_attributes (),
198 options
.get_thread_attributes (),
199 options
.handle_inheritance (),
201 env_buf
, // environment variables
202 options
.working_directory (),
203 options
.startup_info (),
204 &this->process_info_
);
207 # if defined (ACE_HAS_WCHAR) && !defined (ACE_USES_WCHAR)
208 if (options
.use_unicode_environment ())
214 parent (this->getpid ());
215 return this->getpid ();
217 return ACE_INVALID_PID
;
219 #elif defined(ACE_OPENVMS)
220 if (ACE_BIT_ENABLED (options
.creation_flags (),
221 ACE_Process_Options::NO_EXEC
))
222 ACE_NOTSUP_RETURN (ACE_INVALID_PID
);
224 int saved_stdin
= ACE_STDIN
;
225 int saved_stdout
= ACE_STDOUT
;
226 int saved_stderr
= ACE_STDERR
;
227 // Save STD file descriptors and redirect
228 if (options
.get_stdin () != ACE_INVALID_HANDLE
) {
229 if ((saved_stdin
= ACE_OS::dup (ACE_STDIN
)) == -1 && errno
!= EBADF
)
230 ACE_OS::exit (errno
);
231 if (ACE_OS::dup2 (options
.get_stdin (), ACE_STDIN
) == -1)
232 ACE_OS::exit (errno
);
234 if (options
.get_stdout () != ACE_INVALID_HANDLE
) {
235 if ((saved_stdout
= ACE_OS::dup (ACE_STDOUT
)) == -1 && errno
!= EBADF
)
236 ACE_OS::exit (errno
);
237 if (ACE_OS::dup2 (options
.get_stdout (), ACE_STDOUT
) == -1)
238 ACE_OS::exit (errno
);
240 if (options
.get_stderr () != ACE_INVALID_HANDLE
) {
241 if ((saved_stderr
= ACE_OS::dup (ACE_STDERR
)) == -1 && errno
!= EBADF
)
242 ACE_OS::exit (errno
);
243 if (ACE_OS::dup2 (options
.get_stderr (), ACE_STDERR
) == -1)
244 ACE_OS::exit (errno
);
247 if (options
.working_directory () != 0)
248 ACE_NOTSUP_RETURN (ACE_INVALID_PID
);
250 this->child_id_
= vfork();
251 if (this->child_id_
== 0) {
252 ACE_OS::execvp (options
.process_name (),
253 options
.command_line_argv ());
254 // something went wrong
255 this->child_id_
= ACE_INVALID_PID
;
258 // restore STD file descriptors (if necessary)
259 if (options
.get_stdin () != ACE_INVALID_HANDLE
) {
260 if (saved_stdin
== -1)
261 ACE_OS::close (ACE_STDIN
);
263 ACE_OS::dup2 (saved_stdin
, ACE_STDIN
);
265 if (options
.get_stdout () != ACE_INVALID_HANDLE
) {
266 if (saved_stdout
== -1)
267 ACE_OS::close (ACE_STDOUT
);
269 ACE_OS::dup2 (saved_stdout
, ACE_STDOUT
);
271 if (options
.get_stderr () != ACE_INVALID_HANDLE
) {
272 if (saved_stderr
== -1)
273 ACE_OS::close (ACE_STDERR
);
275 ACE_OS::dup2 (saved_stderr
, ACE_STDERR
);
278 return this->child_id_
;
279 #elif defined (ACE_VXWORKS) && defined (__RTP__)
280 if (ACE_BIT_ENABLED (options
.creation_flags (),
281 ACE_Process_Options::NO_EXEC
))
282 ACE_NOTSUP_RETURN (ACE_INVALID_PID
);
284 if (options
.working_directory () != 0)
285 ACE_NOTSUP_RETURN (ACE_INVALID_PID
);
287 int saved_stdin
= ACE_STDIN
;
288 int saved_stdout
= ACE_STDOUT
;
289 int saved_stderr
= ACE_STDERR
;
290 // Save STD file descriptors and redirect
291 if (options
.get_stdin () != ACE_INVALID_HANDLE
) {
292 if ((saved_stdin
= ACE_OS::dup (ACE_STDIN
)) == -1 && errno
!= EBADF
)
293 ACE_OS::exit (errno
);
294 if (ACE_OS::dup2 (options
.get_stdin (), ACE_STDIN
) == -1)
295 ACE_OS::exit (errno
);
297 if (options
.get_stdout () != ACE_INVALID_HANDLE
) {
298 if ((saved_stdout
= ACE_OS::dup (ACE_STDOUT
)) == -1 && errno
!= EBADF
)
299 ACE_OS::exit (errno
);
300 if (ACE_OS::dup2 (options
.get_stdout (), ACE_STDOUT
) == -1)
301 ACE_OS::exit (errno
);
303 if (options
.get_stderr () != ACE_INVALID_HANDLE
) {
304 if ((saved_stderr
= ACE_OS::dup (ACE_STDERR
)) == -1 && errno
!= EBADF
)
305 ACE_OS::exit (errno
);
306 if (ACE_OS::dup2 (options
.get_stderr (), ACE_STDERR
) == -1)
307 ACE_OS::exit (errno
);
310 // Wide-char builds need narrow-char strings for commandline and
311 // environment variables.
312 # if defined (ACE_USES_WCHAR)
313 wchar_t * const *wargv
= options
.command_line_argv ();
315 for (vcount
= 0; wargv
[vcount
] != 0; ++vcount
)
317 char **procargv
= new char *[vcount
+ 1]; // Need 0 at the end
318 procargv
[vcount
] = 0;
319 for (i
= 0; i
< vcount
; ++i
)
320 procargv
[i
] = ACE_Wide_To_Ascii::convert (wargv
[i
]);
323 if (options
.inherit_environment ())
325 wargv
= options
.env_argv ();
326 for (vcount
= 0; wargv
[vcount
] != 0; ++vcount
)
328 procenv
= new char *[vcount
+ 1]; // Need 0 at the end
330 for (i
= 0; i
< vcount
; ++i
)
331 procenv
[i
] = ACE_Wide_To_Ascii::convert (wargv
[i
]);
334 const char **procargv
= const_cast<const char**> (options
.command_line_argv ());
335 const char **procenv
= const_cast<const char**> (options
.env_argv ());
336 # endif /* ACE_USES_WCHAR */
338 this->child_id_
= ::rtpSpawn (procargv
[0],
342 0x10000, // uStackSize
344 VX_FP_TASK
); // taskOptions
345 int my_errno_
= errno
;
346 if (this->child_id_
== ERROR
) {
347 // something went wrong
348 this->child_id_
= ACE_INVALID_PID
;
351 # if defined (ACE_USES_WCHAR)
354 # endif /* ACE_USES_WCHAR */
356 // restore STD file descriptors (if necessary)
357 if (options
.get_stdin () != ACE_INVALID_HANDLE
) {
358 if (saved_stdin
== -1)
359 ACE_OS::close (ACE_STDIN
);
361 ACE_OS::dup2 (saved_stdin
, ACE_STDIN
);
363 if (options
.get_stdout () != ACE_INVALID_HANDLE
) {
364 if (saved_stdout
== -1)
365 ACE_OS::close (ACE_STDOUT
);
367 ACE_OS::dup2 (saved_stdout
, ACE_STDOUT
);
369 if (options
.get_stderr () != ACE_INVALID_HANDLE
) {
370 if (saved_stderr
== -1)
371 ACE_OS::close (ACE_STDERR
);
373 ACE_OS::dup2 (saved_stderr
, ACE_STDERR
);
376 if (this->child_id_
== ACE_INVALID_PID
)
381 return this->child_id_
;
382 #else /* ACE_WIN32 */
383 // Fork the new process.
384 this->child_id_
= ACE::fork (options
.process_name (),
385 options
.avoid_zombies ());
387 if (this->child_id_
== 0)
389 # if !defined (ACE_LACKS_SETPGID)
390 // If we're the child and the options specified a non-default
391 // process group, try to set our pgid to it. This allows the
392 // <ACE_Process_Manager> to wait for processes by their
394 if (options
.getgroup () != ACE_INVALID_PID
395 && ACE_OS::setpgid (0,
396 options
.getgroup ()) < 0)
398 #if !defined (ACE_HAS_THREADS)
399 // We can't emit this log message because ACELIB_ERROR(), etc.
400 // will invoke async signal unsafe functions, which results
401 // in undefined behavior in threaded programs.
402 ACELIB_ERROR ((LM_ERROR
,
404 ACE_TEXT ("ACE_Process::spawn: setpgid failed.")));
407 # endif /* ACE_LACKS_SETPGID */
409 # if !defined (ACE_LACKS_SETREGID)
410 if (options
.getrgid () != (uid_t
) -1
411 || options
.getegid () != (uid_t
) -1)
412 if (ACE_OS::setregid (options
.getrgid (),
413 options
.getegid ()) == -1)
415 #if !defined (ACE_HAS_THREADS)
416 // We can't emit this log message because ACELIB_ERROR(), etc.
417 // will invoke async signal unsafe functions, which results
418 // in undefined behavior in threaded programs.
419 ACELIB_ERROR ((LM_ERROR
,
421 ACE_TEXT ("ACE_Process::spawn: setregid failed.")));
424 # endif /* ACE_LACKS_SETREGID */
426 # if !defined (ACE_LACKS_SETREUID)
427 // Set user and group id's.
428 if (options
.getruid () != (uid_t
) -1
429 || options
.geteuid () != (uid_t
) -1)
430 if (ACE_OS::setreuid (options
.getruid (),
431 options
.geteuid ()) == -1)
433 #if !defined (ACE_HAS_THREADS)
434 // We can't emit this log message because ACELIB_ERROR(), etc.
435 // will invoke async signal unsafe functions, which results
436 // in undefined behavior in threaded programs.
437 ACELIB_ERROR ((LM_ERROR
,
439 ACE_TEXT ("ACE_Process::spawn: setreuid failed.")));
442 # endif /* ACE_LACKS_SETREUID */
444 this->child (ACE_OS::getppid ());
446 else if (this->child_id_
!= -1)
447 this->parent (this->child_id_
);
449 // If we're not supposed to exec, return the process id.
450 if (ACE_BIT_ENABLED (options
.creation_flags (),
451 ACE_Process_Options::NO_EXEC
))
452 return this->child_id_
;
454 switch (this->child_id_
)
456 case static_cast<pid_t
>(-1):
458 return ACE_INVALID_PID
;
460 // Child process...exec the
462 if (options
.get_stdin () != ACE_INVALID_HANDLE
463 && ACE_OS::dup2 (options
.get_stdin (),
465 ACE_OS::exit (errno
);
466 else if (options
.get_stdout () != ACE_INVALID_HANDLE
467 && ACE_OS::dup2 (options
.get_stdout (),
469 ACE_OS::exit (errno
);
470 else if (options
.get_stderr () != ACE_INVALID_HANDLE
471 && ACE_OS::dup2 (options
.get_stderr (),
473 ACE_OS::exit (errno
);
475 // close down unneeded descriptors
476 ACE_OS::close (options
.get_stdin ());
477 ACE_OS::close (options
.get_stdout ());
478 ACE_OS::close (options
.get_stderr ());
479 if (!options
.handle_inheritance ())
481 // Set close-on-exec for all FDs except standard handles
482 for (int i
= ACE::max_handles () - 1; i
>= 0; i
--)
484 if (i
== ACE_STDIN
|| i
== ACE_STDOUT
|| i
== ACE_STDERR
)
486 ACE_OS::fcntl (i
, F_SETFD
, FD_CLOEXEC
);
490 // If we must, set the working directory for the child
492 if (options
.working_directory () != 0)
493 ACE_OS::chdir (options
.working_directory ());
494 // Should check for error here!
496 // Child process executes the command.
499 // Wide-char builds not on Windows need narrow-char strings for
500 // exec() and environment variables. Don't need to worry about
501 // releasing any of the converted string memory since this
502 // process will either exec() or exit() shortly.
503 # if defined (ACE_USES_WCHAR)
504 ACE_Wide_To_Ascii
n_procname (options
.process_name ());
505 const char *procname
= n_procname
.char_rep ();
507 wchar_t * const *wargv
= options
.command_line_argv ();
509 for (vcount
= 0; wargv
[vcount
] != 0; ++vcount
)
511 char **procargv
= new char *[vcount
+ 1]; // Need 0 at the end
512 procargv
[vcount
] = 0;
513 for (i
= 0; i
< vcount
; ++i
)
514 procargv
[i
] = ACE_Wide_To_Ascii::convert (wargv
[i
]);
516 wargv
= options
.env_argv ();
517 for (vcount
= 0; wargv
[vcount
] != 0; ++vcount
)
519 char **procenv
= new char *[vcount
+ 1]; // Need 0 at the end
521 for (i
= 0; i
< vcount
; ++i
)
522 procenv
[i
] = ACE_Wide_To_Ascii::convert (wargv
[i
]);
524 const char *procname
= options
.process_name ();
525 char *const *procargv
= options
.command_line_argv ();
526 char *const *procenv
= options
.env_argv ();
527 # endif /* ACE_USES_WCHAR */
529 if (options
.inherit_environment ())
531 // Add the new environment variables to the environment
532 // context of the context before doing an <execvp>.
533 for (size_t i
= 0; procenv
[i
] != 0; i
++)
534 if (ACE_OS::putenv (procenv
[i
]) != 0)
535 return ACE_INVALID_PID
;
537 // Now the forked process has both inherited variables and
538 // the user's supplied variables.
539 # ifdef ACE_LACKS_EXECVP
540 result
= ACE_OS::execv (procname
, procargv
);
542 result
= ACE_OS::execvp (procname
, procargv
);
547 result
= ACE_OS::execve (procname
, procargv
, procenv
);
551 // If the execv fails, this child needs to exit.
553 // Exit with the errno so that the calling process can
554 // catch this and figure out what went wrong.
555 ACE_OS::_exit (errno
);
557 // ... otherwise, this is never reached.
561 // Server process. The fork succeeded.
562 return this->child_id_
;
564 #endif /* ACE_WIN32 */
568 ACE_Process::parent (pid_t
)
574 ACE_Process::child (pid_t
)
580 ACE_Process::unmanage (void)
586 ACE_Process::running (void) const
588 #if defined (ACE_WIN32)
591 BOOL result
= ::GetExitCodeProcess (this->gethandle (),
593 return result
&& code
== STILL_ACTIVE
;
595 if (ACE_INVALID_PID
== this->getpid ())
598 return ACE_OS::kill (this->getpid (),
601 #endif /* ACE_WIN32 */
605 ACE_Process::wait (const ACE_Time_Value
&tv
,
606 ACE_exitcode
*status
)
608 #if defined (ACE_WIN32)
609 // Don't try to get the process exit status if wait failed so we can
610 // keep the original error code intact.
611 switch (::WaitForSingleObject (process_info_
.hProcess
,
615 // The error status of <GetExitCodeProcess> is nonetheless not
616 // tested because we don't know how to return the value.
617 ::GetExitCodeProcess (process_info_
.hProcess
,
620 *status
= this->exit_code_
;
621 return this->getpid ();
626 ACE_OS::set_errno_to_last_error ();
629 #elif defined(ACE_LACKS_UNIX_SIGNALS)
630 if (tv
== ACE_Time_Value::zero
)
633 ACE_OS::waitpid (this->child_id_
,
637 *status
= this->exit_code_
;
642 if (tv
== ACE_Time_Value::max_time
)
643 # if defined (ACE_VXWORKS)
646 while ((retv
= this->wait (status
)) == ACE_INVALID_PID
&& errno
== EINTR
) ;
650 return this->wait (status
);
654 ACE_Time_Value
sleeptm (1); // 1 msec
655 if (sleeptm
> tv
) // if sleeptime > waittime
657 ACE_Time_Value
tmo (tv
); // Need one we can change
658 for (ACE_Countdown_Time
time_left (&tmo
); tmo
> ACE_Time_Value::zero
; time_left
.update ())
660 pid
= ACE_OS::waitpid (this->getpid (),
664 *status
= this->exit_code_
;
666 if (pid
> 0 || pid
== ACE_INVALID_PID
)
667 break; // Got a child or an error - all done
669 // pid 0, nothing is ready yet, so wait.
670 // Do a (very) short sleep (only this thread sleeps).
671 ACE_OS::sleep (sleeptm
);
675 #else /* !ACE_WIN32 && !ACE_LACKS_UNIX_SIGNALS */
676 if (tv
== ACE_Time_Value::zero
)
679 ACE_OS::waitpid (this->child_id_
,
683 *status
= this->exit_code_
;
688 if (tv
== ACE_Time_Value::max_time
)
689 return this->wait (status
);
691 // Need to wait but limited to specified time.
692 // Force generation of SIGCHLD, even though we don't want to
693 // catch it - just need it to interrupt the sleep below.
694 // If this object has a reactor set, assume it was given at
695 // open(), and there's already a SIGCHLD action set, so no
696 // action is needed here.
697 ACE_Sig_Action old_action
;
698 ACE_Sig_Action
do_sigchld ((ACE_SignalHandler
)sigchld_nop
);
699 do_sigchld
.register_action (SIGCHLD
, &old_action
);
702 ACE_Time_Value
tmo (tv
); // Need one we can change
703 for (ACE_Countdown_Time
time_left (&tmo
); ; time_left
.update ())
705 pid
= ACE_OS::waitpid (this->getpid (),
709 *status
= this->exit_code_
;
711 if (pid
> 0 || pid
== ACE_INVALID_PID
)
712 break; // Got a child or an error - all done
714 // pid 0, nothing is ready yet, so wait.
715 // Do a sleep (only this thread sleeps) til something
716 // happens. This relies on SIGCHLD interrupting the sleep.
717 // If SIGCHLD isn't delivered, we'll need to do something
718 // with sigaction to force it.
719 if (-1 == ACE_OS::sleep (tmo
) && errno
== EINTR
)
726 // Restore the previous SIGCHLD action if it was changed.
727 old_action
.register_action (SIGCHLD
);
730 #endif /* ACE_WIN32 */
734 ACE_Process::close_dup_handles (void)
736 if (this->dup_handles_
.num_set () > 0)
738 ACE_Handle_Set_Iterator
h_iter (this->dup_handles_
);
739 for (ACE_HANDLE h
= h_iter ();
740 h
!= ACE_INVALID_HANDLE
;
742 ACE_OS::closesocket (h
);
743 this->dup_handles_
.reset ();
749 ACE_Process::close_passed_handles (void)
751 if (this->handles_passed_
.num_set () > 0)
753 ACE_Handle_Set_Iterator
h_iter (this->handles_passed_
);
754 for (ACE_HANDLE h
= h_iter ();
755 h
!= ACE_INVALID_HANDLE
;
757 ACE_OS::closesocket (h
);
758 this->handles_passed_
.reset ();
763 #if defined (ACE_WIN32) && \
764 defined (ACE_HAS_WCHAR) && !defined (ACE_USES_WCHAR) && \
765 !defined (ACE_HAS_WINCE)
767 ACE_Process::convert_env_buffer (const char* env
) const
769 // Total starts out at 1 due to the final block nul terminator
772 // Convert each individual character string to the equivalent wide
774 ACE_Vector
<wchar_t*> buffer
;
781 // Convert the char string to wchar_t
782 wchar_t* str
= ACE_Ascii_To_Wide::convert (env
+ start
);
784 // Add the length of the string plus the nul terminator
785 total
+= ACE_OS::strlen (str
) + 1;
787 // Save it and set up for the next string
788 buffer
.push_back (str
);
790 if (env
[start
] == '\0')
795 i
+= ACE_OS::strlen (env
+ i
);
799 // Copy each string into the buffer leaving a nul terminator between
800 // each string and adding a second nul terminator at the end
802 wchar_t* wenv
= new wchar_t[total
];
803 size_t length
= buffer
.size ();
804 for (i
= 0; i
< length
; ++i
)
806 ACE_OS::strcpy(wenv
+ start
, buffer
[i
]);
807 start
+= ACE_OS::strlen (buffer
[i
]) + 1;
815 ACE_Process_Options::ACE_Process_Options (bool inherit_environment
,
816 size_t command_line_buf_len
,
819 size_t max_cmdline_args
)
821 #if !defined (ACE_HAS_WINCE)
822 inherit_environment_ (inherit_environment
),
823 #endif /* ACE_HAS_WINCE */
826 #if !defined (ACE_HAS_WINCE)
827 #if defined (ACE_WIN32)
828 environment_inherited_ (0),
829 process_attributes_ (0),
830 thread_attributes_ (0),
831 user_token_ (ACE_INVALID_HANDLE
),
832 close_user_token_ (false),
833 #else /* ACE_WIN32 */
834 stdin_ (ACE_INVALID_HANDLE
),
835 stdout_ (ACE_INVALID_HANDLE
),
836 stderr_ (ACE_INVALID_HANDLE
),
841 #endif /* ACE_WIN32 */
842 handle_inheritance_ (true),
843 set_handles_called_ (0),
844 environment_buf_index_ (0),
845 environment_argv_index_ (0),
846 environment_buf_ (0),
847 environment_buf_len_ (env_buf_len
),
848 max_environment_args_ (max_env_args
),
849 max_environ_argv_index_ (max_env_args
- 1),
850 #endif /* !ACE_HAS_WINCE */
851 command_line_argv_calculated_ (false),
852 command_line_buf_ (0),
853 command_line_copy_ (0),
854 command_line_buf_len_ (command_line_buf_len
),
855 max_command_line_args_ (max_cmdline_args
),
856 command_line_argv_ (0),
857 process_group_ (ACE_INVALID_PID
),
858 use_unicode_environment_ (false)
860 #if defined (ACE_HAS_ALLOC_HOOKS)
861 ACE_ALLOCATOR (command_line_buf_
,
862 static_cast<ACE_TCHAR
*>(ACE_Allocator::instance()->malloc(sizeof(ACE_TCHAR
) * command_line_buf_len
)));
864 ACE_NEW (command_line_buf_
,
865 ACE_TCHAR
[command_line_buf_len
]);
866 #endif /* ACE_HAS_ALLOC_HOOKS */
867 command_line_buf_
[0] = '\0';
868 process_name_
[0] = '\0';
870 #if defined (ACE_HAS_WINCE)
871 ACE_UNUSED_ARG(inherit_environment
);
872 ACE_UNUSED_ARG(env_buf_len
);
873 ACE_UNUSED_ARG(max_env_args
);
876 #if !defined (ACE_HAS_WINCE)
877 working_directory_
[0] = '\0';
878 #if defined (ACE_HAS_ALLOC_HOOKS)
879 ACE_ALLOCATOR (environment_buf_
,
880 static_cast<ACE_TCHAR
*>(ACE_Allocator::instance()->malloc(sizeof(ACE_TCHAR
) * env_buf_len
)));
882 ACE_NEW (environment_buf_
,
883 ACE_TCHAR
[env_buf_len
]);
884 #endif /* ACE_HAS_ALLOC_HOOKS */
885 #if defined (ACE_HAS_ALLOC_HOOKS)
886 ACE_ALLOCATOR (environment_argv_
,
887 static_cast<ACE_TCHAR
**>(ACE_Allocator::instance()->malloc(sizeof(ACE_TCHAR
*) * max_env_args
)));
889 ACE_NEW (environment_argv_
,
890 ACE_TCHAR
*[max_env_args
]);
891 #endif /* ACE_HAS_ALLOC_HOOKS */
892 environment_buf_
[0] = '\0';
893 environment_argv_
[0] = 0;
894 #if defined (ACE_WIN32)
895 ACE_OS::memset ((void *) &this->startup_info_
,
897 sizeof this->startup_info_
);
898 this->startup_info_
.cb
= sizeof this->startup_info_
;
899 #endif /* ACE_WIN32 */
900 #endif /* !ACE_HAS_WINCE */
901 #if defined (ACE_HAS_ALLOC_HOOKS)
902 ACE_ALLOCATOR (command_line_argv_
,
903 static_cast<ACE_TCHAR
**>(ACE_Allocator::instance()->malloc(sizeof(ACE_TCHAR
*) * max_cmdline_args
)));
905 ACE_NEW (command_line_argv_
,
906 ACE_TCHAR
*[max_cmdline_args
]);
907 #endif /* ACE_HAS_ALLOC_HOOKS */
910 #if !defined (ACE_HAS_WINCE)
911 #if defined (ACE_WIN32)
913 ACE_Process_Options::inherit_environment (void)
915 // Ensure only once execution.
916 if (environment_inherited_
)
918 environment_inherited_
= 1;
920 // Get the existing environment.
921 ACE_TCHAR
*existing_environment
= 0;
922 #if defined (ACE_HAS_WCHAR) && !defined (ACE_USES_WCHAR)
923 WCHAR
*existing_wide_env
= 0;
924 ACE_Vector
<char> temp_narrow_env
;
925 if (this->use_unicode_environment_
)
927 existing_wide_env
= ::GetEnvironmentStringsW ();
928 for (WCHAR
*iter
= existing_wide_env
; *iter
; ++iter
)
930 ACE_Wide_To_Ascii
wta (iter
);
931 size_t len
= ACE_OS::strlen (wta
.char_rep ());
932 size_t idx
= temp_narrow_env
.size ();
933 temp_narrow_env
.resize (idx
+ len
+ 1, 0);
934 ACE_OS::strncpy (&temp_narrow_env
[idx
], wta
.char_rep (), len
);
937 temp_narrow_env
.push_back (0);
938 existing_environment
= &temp_narrow_env
[0];
942 existing_environment
= ACE_OS::getenvstrings ();
946 while (existing_environment
[slot
] != '\0')
948 size_t len
= ACE_OS::strlen (existing_environment
+ slot
);
950 // Add the string to our env buffer.
951 if (this->setenv_i (existing_environment
+ slot
, len
) == -1)
953 ACELIB_ERROR ((LM_ERROR
,
955 ACE_TEXT ("ACE_Process_Options::ACE_Process_Options")));
959 // Skip to the next word.
963 #if defined (ACE_HAS_WCHAR) && !defined (ACE_USES_WCHAR)
964 if (this->use_unicode_environment_
)
965 ::FreeEnvironmentStringsW (existing_wide_env
);
968 ACE_TEXT_FreeEnvironmentStrings (existing_environment
);
971 #else /* defined ACE_WIN32 */
974 ACE_Process_Options::env_argv (void)
976 return environment_argv_
;
979 #endif /* ACE_WIN32 */
982 ACE_Process_Options::setenv (ACE_TCHAR
*envp
[])
987 if (this->setenv_i (envp
[i
],
988 ACE_OS::strlen (envp
[i
])) == -1)
993 #if defined (ACE_WIN32)
994 if (inherit_environment_
)
995 this->inherit_environment ();
996 #endif /* ACE_WIN32 */
1001 #ifndef ACE_LACKS_VA_FUNCTIONS
1003 ACE_Process_Options::setenv (const ACE_TCHAR
*format
, ...)
1005 ACE_TCHAR stack_buf
[DEFAULT_COMMAND_LINE_BUF_LEN
];
1009 va_start (argp
, format
);
1011 // Add the rest of the varargs.
1012 int status
= ACE_OS::vsnprintf (stack_buf
, DEFAULT_COMMAND_LINE_BUF_LEN
,
1020 // Append the string to are environment buffer.
1021 if (this->setenv_i (stack_buf
,
1022 ACE_OS::strlen (stack_buf
)) == -1)
1025 #if defined (ACE_WIN32)
1026 if (inherit_environment_
)
1027 this->inherit_environment ();
1028 #endif /* ACE_WIN32 */
1034 ACE_Process_Options::setenv (const ACE_TCHAR
*variable_name
,
1035 const ACE_TCHAR
*format
, ...)
1037 // To address the potential buffer overflow,
1038 // we now allocate the buffer on heap with a variable size.
1039 size_t const buflen
= ACE_OS::strlen (variable_name
) + ACE_OS::strlen (format
) + 2;
1040 ACE_TCHAR
*newformat
= 0;
1041 ACE_NEW_RETURN (newformat
, ACE_TCHAR
[buflen
], -1);
1042 ACE_Auto_Basic_Array_Ptr
<ACE_TCHAR
> safe_newformat (newformat
);
1044 # if !defined (ACE_WIN32) && defined (ACE_USES_WCHAR)
1045 const ACE_TCHAR
*fmt
= ACE_TEXT ("%ls=%ls");
1047 const ACE_TCHAR
*fmt
= ACE_TEXT ("%s=%s");
1050 // Add in the variable name.
1051 ACE_OS::snprintf (safe_newformat
.get (), buflen
, fmt
,
1052 variable_name
, format
);
1054 // Add the rest of the varargs.
1055 size_t tmp_buflen
= buflen
;
1056 if (DEFAULT_COMMAND_LINE_BUF_LEN
> buflen
)
1058 tmp_buflen
= DEFAULT_COMMAND_LINE_BUF_LEN
;
1062 ACE_TCHAR
*stack_buf
= 0;
1063 ACE_NEW_RETURN (stack_buf
, ACE_TCHAR
[tmp_buflen
], -1);
1064 ACE_Auto_Basic_Array_Ptr
<ACE_TCHAR
> safe_stack_buf (stack_buf
);
1068 // Must restart varargs on each time through this loop,
1070 va_start (argp
, format
);
1072 retval
= ACE_OS::vsnprintf (safe_stack_buf
.get (), tmp_buflen
, safe_newformat
.get (), argp
);
1077 if (retval
> ACE_Utils::truncate_cast
<int> (tmp_buflen
))
1080 ACE_NEW_RETURN (stack_buf
, ACE_TCHAR
[tmp_buflen
], -1);
1081 safe_stack_buf
.reset (stack_buf
);
1090 // In case that vsnprintf is not supported,
1091 // e.g., LynxOS and VxWorks 5, we have to
1092 // fall back to vsprintf.
1093 if (errno
== ENOTSUP
)
1095 // ALERT: Since we have to use vsprintf here, there is still a chance that
1096 // the stack_buf overflows, i.e., the length of the resulting string
1097 // can still possibly go beyond the allocated stack_buf.
1099 va_start (argp
, format
);
1100 retval
= ACE_OS::vsprintf (safe_stack_buf
.get (), safe_newformat
.get (), argp
);
1103 // vsprintf is failed.
1107 // vsnprintf is failed.
1111 // Append the string to our environment buffer.
1112 if (this->setenv_i (safe_stack_buf
.get (),
1113 ACE_OS::strlen (safe_stack_buf
.get ())) == -1)
1116 #if defined (ACE_WIN32)
1117 if (inherit_environment_
)
1118 this->inherit_environment ();
1119 #endif /* ACE_WIN32 */
1123 #endif // ACE_LACKS_VA_FUNCTIONS
1126 ACE_Process_Options::setenv_i (ACE_TCHAR
*assignment
,
1129 // Add one for the null char.
1132 // If environment larger than allocated buffer return. Also check to
1133 // make sure we have enough room.
1134 if (environment_argv_index_
== max_environ_argv_index_
1135 || (len
+ environment_buf_index_
) >= environment_buf_len_
)
1138 // Copy the new environment string.
1139 ACE_OS::memcpy (environment_buf_
+ environment_buf_index_
,
1141 len
* sizeof (ACE_TCHAR
));
1143 // Update the argv array.
1144 environment_argv_
[environment_argv_index_
++] =
1145 environment_buf_
+ environment_buf_index_
;
1146 environment_argv_
[environment_argv_index_
] = 0;
1148 // Update our index.
1149 environment_buf_index_
+= len
;
1151 // Make sure the buffer is null-terminated.
1152 environment_buf_
[environment_buf_index_
] = '\0';
1157 ACE_Process_Options::set_handles (ACE_HANDLE std_in
,
1161 this->set_handles_called_
= 1;
1162 #if defined (ACE_WIN32)
1164 // Tell the new process to use our std handles.
1165 this->startup_info_
.dwFlags
= STARTF_USESTDHANDLES
;
1167 if (std_in
== ACE_INVALID_HANDLE
)
1169 if (std_out
== ACE_INVALID_HANDLE
)
1170 std_out
= ACE_STDOUT
;
1171 if (std_err
== ACE_INVALID_HANDLE
)
1172 std_err
= ACE_STDERR
;
1174 // STD handles may have value 0 (not ACE_INVALID_HANDLE) if there is no such
1175 // handle in the process. This was observed to occur for stdin in console
1176 // processes that were launched from services. In this case we need to make
1177 // sure not to return -1 from setting std_in so that we can process std_out
1182 if (!::DuplicateHandle (::GetCurrentProcess (),
1184 ::GetCurrentProcess (),
1185 &this->startup_info_
.hStdInput
,
1188 DUPLICATE_SAME_ACCESS
))
1194 if (!::DuplicateHandle (::GetCurrentProcess (),
1196 ::GetCurrentProcess (),
1197 &this->startup_info_
.hStdOutput
,
1200 DUPLICATE_SAME_ACCESS
))
1206 if (!::DuplicateHandle (::GetCurrentProcess (),
1208 ::GetCurrentProcess (),
1209 &this->startup_info_
.hStdError
,
1212 DUPLICATE_SAME_ACCESS
))
1215 #else /* ACE_WIN32 */
1216 this->stdin_
= ACE_OS::dup (std_in
);
1217 this->stdout_
= ACE_OS::dup (std_out
);
1218 this->stderr_
= ACE_OS::dup (std_err
);
1219 #endif /* ACE_WIN32 */
1221 return 0; // Success.
1226 ACE_Process_Options::release_handles ()
1228 if (set_handles_called_
)
1230 #if defined (ACE_WIN32)
1231 ACE_OS::close (startup_info_
.hStdInput
);
1232 ACE_OS::close (startup_info_
.hStdOutput
);
1233 ACE_OS::close (startup_info_
.hStdError
);
1234 #else /* ACE_WIN32 */
1235 ACE_OS::close (stdin_
);
1236 ACE_OS::close (stdout_
);
1237 ACE_OS::close (stderr_
);
1238 #endif /* ACE_WIN32 */
1239 set_handles_called_
= 0;
1242 #endif /* !ACE_HAS_WINCE */
1245 ACE_Process_Options::~ACE_Process_Options (void)
1247 #if !defined (ACE_HAS_WINCE)
1249 #if defined (ACE_HAS_ALLOC_HOOKS)
1250 ACE_Allocator::instance()->free(environment_buf_
);
1251 ACE_Allocator::instance()->free(environment_argv_
);
1253 delete [] environment_buf_
;
1254 delete [] environment_argv_
;
1255 #endif /* ACE_HAS_ALLOC_HOOKS */
1256 #endif /* !ACE_HAS_WINCE */
1257 #if defined (ACE_HAS_ALLOC_HOOKS)
1258 ACE_Allocator::instance()->free(command_line_buf_
);
1260 delete [] command_line_buf_
;
1261 #endif /* ACE_HAS_ALLOC_HOOKS */
1262 ACE::strdelete (command_line_copy_
);
1263 #if defined (ACE_HAS_ALLOC_HOOKS)
1264 ACE_Allocator::instance()->free(command_line_argv_
);
1266 delete [] command_line_argv_
;
1267 #endif /* ACE_HAS_ALLOC_HOOKS */
1269 #if defined (ACE_WIN32)
1270 if (user_token_
!= ACE_INVALID_HANDLE
&& close_user_token_
)
1272 ::CloseHandle(user_token_
);
1274 #endif /* ACE_WIN32 */
1278 ACE_Process_Options::command_line (const ACE_TCHAR
*const argv
[])
1284 ACE_OS::strcat (command_line_buf_
, argv
[i
]);
1288 // Check to see if the next argument will overflow the
1289 // command_line buffer.
1290 size_t const cur_len
=
1291 ACE_OS::strlen (command_line_buf_
)
1292 + ACE_OS::strlen (argv
[i
])
1295 if (cur_len
> command_line_buf_len_
)
1297 ACELIB_ERROR_RETURN ((LM_ERROR
,
1298 ACE_TEXT ("ACE_Process:command_line: ")
1299 ACE_TEXT ("command line is ")
1300 ACE_TEXT ("longer than %d\n"),
1301 command_line_buf_len_
),
1305 ACE_OS::strcat (command_line_buf_
, ACE_TEXT (" "));
1306 ACE_OS::strcat (command_line_buf_
, argv
[i
]);
1310 command_line_argv_calculated_
= false;
1311 return 0; // Success.
1314 #ifndef ACE_LACKS_VA_FUNCTIONS
1316 ACE_Process_Options::command_line (const ACE_TCHAR
*format
, ...)
1318 // Store all ... args in argp.
1320 va_start (argp
, format
);
1322 if (command_line_buf_len_
< 1)
1328 ACE_OS::vsnprintf (command_line_buf_
,
1329 command_line_buf_len_
,
1335 command_line_argv_calculated_
= false;
1339 #if defined (ACE_HAS_WCHAR) && !defined (ACE_HAS_WINCE)
1341 * @note Not available on Windows CE because it doesn't have a char version of
1345 ACE_Process_Options::command_line (const ACE_ANTI_TCHAR
*format
, ...)
1347 ACE_ANTI_TCHAR
*anti_clb
= 0;
1348 ACE_NEW_RETURN (anti_clb
,
1349 ACE_ANTI_TCHAR
[this->command_line_buf_len_
],
1352 // Store all ... args in argp.
1354 va_start (argp
, format
);
1356 // sprintf the format and args into command_line_buf_.
1357 ACE_OS::vsnprintf (anti_clb
, this->command_line_buf_len_
, format
, argp
);
1362 ACE_OS::strcpy (this->command_line_buf_
,
1363 ACE_TEXT_ANTI_TO_TCHAR (anti_clb
));
1367 command_line_argv_calculated_
= false;
1370 #endif /* ACE_HAS_WCHAR && !ACE_HAS_WINCE */
1371 #endif // ACE_LACKS_VA_FUNCTIONS
1374 ACE_Process_Options::env_buf (void)
1376 #if !defined (ACE_HAS_WINCE)
1377 if (environment_buf_
[0] == '\0')
1380 return environment_buf_
;
1383 #endif /* !ACE_HAS_WINCE */
1387 ACE_Process_Options::command_line_argv (void)
1389 if (!command_line_argv_calculated_
)
1391 command_line_argv_calculated_
= true;
1393 // We need to free up any previous allocated memory first.
1394 ACE::strdelete (command_line_copy_
);
1396 // We need to make a dynamically allocated copy here since
1397 // ACE_Tokenizer modifies its arguments.
1398 command_line_copy_
= ACE::strnew (command_line_buf_
);
1399 // This tokenizer will replace all spaces with end-of-string
1400 // characters and will preserve text between "" and '' pairs.
1401 ACE_Tokenizer
parser (command_line_copy_
);
1402 parser
.delimiter_replace (' ', '\0');
1403 parser
.preserve_designators ('\"', '\"'); // "
1404 parser
.preserve_designators ('\'', '\'');
1408 command_line_argv_
[x
] = parser
.next ();
1409 while (command_line_argv_
[x
] != 0
1410 // subtract one for the ending zero.
1411 && ++x
< max_command_line_args_
- 1);
1413 command_line_argv_
[x
] = 0;
1416 return command_line_argv_
;
1419 // Cause the specified handle to be passed to a child process
1420 // when it's spawned.
1422 ACE_Process_Options::pass_handle (ACE_HANDLE h
)
1424 #if defined (ACE_HAS_WINCE)
1425 ACE_NOTSUP_RETURN (-1);
1427 this->handles_passed_
.set_bit (h
);
1429 #endif /* ACE_HAS_WINCE */
1432 // Get a copy of the handles the ACE_Process_Options duplicated
1433 // for the spawned process.
1435 ACE_Process_Options::dup_handles (ACE_Handle_Set
&set
) const
1437 if (this->dup_handles_
.num_set () == 0)
1440 set
= this->dup_handles_
;
1444 // Get a copy of the handles passed to the spawned process. This
1445 // will be the set of handles previously passed to @arg pass_handle().
1447 ACE_Process_Options::passed_handles (ACE_Handle_Set
&set
) const
1449 if (this->handles_passed_
.num_set () == 0)
1452 set
= this->handles_passed_
;
1456 ACE_Managed_Process::~ACE_Managed_Process (void)
1460 ACE_ALLOC_HOOK_DEFINE(ACE_Managed_Process
)
1463 ACE_Managed_Process::unmanage (void)
1468 #if defined (ACE_WIN32)
1470 ACE_Process_Options::set_user_token (HANDLE token
, bool close_token
)
1472 if (user_token_
!= ACE_INVALID_HANDLE
&& close_user_token_
)
1474 ::CloseHandle(user_token_
);
1477 user_token_
= token
;
1478 close_user_token_
= close_token
;
1480 #endif /* ACE_WIN32 */
1482 ACE_END_VERSIONED_NAMESPACE_DECL