1 #include "ace/Process.h"
3 #if !defined (__ACE_INLINE__)
4 #include "ace/Process.inl"
5 #endif /* __ACE_INLINE__ */
8 #include "ace/Signal.h"
9 #include "ace/SString.h"
10 #include "ace/Log_Category.h"
11 #include "ace/OS_NS_stdio.h"
12 #include "ace/OS_NS_stdlib.h"
13 #include "ace/OS_NS_sys_socket.h"
14 #include "ace/OS_NS_errno.h"
15 #include "ace/OS_NS_string.h"
16 #include "ace/OS_NS_unistd.h"
17 #include "ace/OS_NS_fcntl.h"
18 #include "ace/OS_Memory.h"
19 #include "ace/Countdown_Time.h"
20 #include "ace/Truncate.h"
21 #include "ace/Vector_T.h"
22 #include "ace/Tokenizer_T.h"
24 #if defined (ACE_VXWORKS) && defined (__RTP__)
31 // This function acts as a signal handler for SIGCHLD. We don't really want
32 // to do anything with the signal - it's just needed to interrupt a sleep.
33 // See wait() for more info.
34 #if !defined (ACE_WIN32) && !defined(ACE_LACKS_UNIX_SIGNALS)
35 static void sigchld_nop (int, siginfo_t
*, ucontext_t
*)
39 #endif /* ACE_WIN32 */
41 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
43 ACE_Process::ACE_Process ()
45 #if !defined (ACE_WIN32)
46 child_id_ (ACE_INVALID_PID
),
47 #endif /* !defined (ACE_WIN32) */
50 #if defined (ACE_WIN32)
51 ACE_OS::memset ((void *) &this->process_info_
,
53 sizeof this->process_info_
);
54 #endif /* ACE_WIN32 */
57 ACE_Process::~ACE_Process ()
59 #if defined (ACE_WIN32)
60 // Free resources allocated in kernel.
61 ACE_OS::close (this->process_info_
.hThread
);
62 ACE_OS::close (this->process_info_
.hProcess
);
63 #endif /* ACE_WIN32 */
64 // If any handles were duplicated for the child process and
65 // still not closed, get them now.
66 this->close_dup_handles ();
70 ACE_Process::prepare (ACE_Process_Options
&)
76 ACE_Process::spawn (ACE_Process_Options
&options
)
78 if (this->prepare (options
) < 0)
79 return ACE_INVALID_PID
;
81 // Stash the passed/duped handle sets away in this object for later
82 // closing if needed or requested. At the same time, figure out which
83 // ones to include in command line options if that's needed below.
84 ACE_Handle_Set
*set_p
= 0;
85 if (options
.dup_handles (this->dup_handles_
))
86 set_p
= &this->dup_handles_
;
87 else if (options
.passed_handles (this->handles_passed_
))
88 set_p
= &this->handles_passed_
;
90 // If we are going to end up running a new program (i.e. Win32, or
91 // NO_EXEC option is set) then get any handles passed in the options,
92 // and tack them onto the command line with +H <handle> options,
93 // unless the command line runs out of space.
94 // Note that we're using the knowledge that all the options, argvs, etc.
95 // passed to the options are all sitting in the command_line_buf. Any
96 // call to get the argv then splits them out. So, regardless of the
97 // platform, tack them all onto the command line buf and take it
99 if (set_p
&& !ACE_BIT_ENABLED (options
.creation_flags (),
100 ACE_Process_Options::NO_EXEC
))
103 ACE_TCHAR
*cmd_line_buf
= options
.command_line_buf (&max_len
);
104 size_t curr_len
= ACE_OS::strlen (cmd_line_buf
);
105 ACE_Handle_Set_Iterator
h_iter (*set_p
);
106 // Because the length of the to-be-formatted +H option is not
107 // known, and we don't have a snprintf, guess at the space
108 // needed (20 chars), and use that as a limit.
109 for (ACE_HANDLE h
= h_iter ();
110 h
!= ACE_INVALID_HANDLE
&& curr_len
+ 20 < max_len
;
113 #if defined (ACE_WIN32)
114 # if defined (ACE_WIN64)
115 // silence warnings coming from MinGW64 compilers
116 # if defined (__GNUC__)
117 # pragma GCC diagnostic push
118 # pragma GCC diagnostic ignored "-Wformat"
119 # pragma GCC diagnostic ignored "-Wformat-extra-args"
120 # endif /* __GNUC__ */
121 curr_len
+= ACE_OS::sprintf (&cmd_line_buf
[curr_len
],
122 ACE_TEXT (" +H %I64p"),
124 # if defined (__GNUC__)
125 # pragma GCC diagnostic pop
126 # endif /* __GNUC__ */
128 curr_len
+= ACE_OS::sprintf (&cmd_line_buf
[curr_len
],
131 # endif /* ACE_WIN64 */
133 curr_len
+= ACE_OS::sprintf (&cmd_line_buf
[curr_len
],
136 #endif /* ACE_WIN32 */
140 #if defined (ACE_WIN32)
141 void* env_buf
= options
.env_buf ();
142 DWORD flags
= options
.creation_flags ();
143 # if defined (ACE_HAS_WCHAR) && !defined (ACE_USES_WCHAR)
144 wchar_t* wenv_buf
= 0;
145 if (options
.use_unicode_environment ())
147 wenv_buf
= this->convert_env_buffer (options
.env_buf ());
149 flags
|= CREATE_UNICODE_ENVIRONMENT
;
154 if (options
.get_user_token () == ACE_INVALID_HANDLE
)
156 fork_result
= ACE_TEXT_CreateProcess (0,
157 options
.command_line_buf (),
158 options
.get_process_attributes (),
159 options
.get_thread_attributes (),
160 options
.handle_inheritance (),
162 env_buf
, // environment variables
163 options
.working_directory (),
164 options
.startup_info (),
165 &this->process_info_
);
169 fork_result
= ACE_TEXT_CreateProcessAsUser (options
.get_user_token (),
171 options
.command_line_buf (),
172 options
.get_process_attributes (),
173 options
.get_thread_attributes (),
174 options
.handle_inheritance (),
176 env_buf
, // environment variables
177 options
.working_directory (),
178 options
.startup_info (),
179 &this->process_info_
);
182 # if defined (ACE_HAS_WCHAR) && !defined (ACE_USES_WCHAR)
183 if (options
.use_unicode_environment ())
189 parent (this->getpid ());
190 return this->getpid ();
192 return ACE_INVALID_PID
;
193 #elif defined (ACE_VXWORKS) && defined (__RTP__)
194 if (ACE_BIT_ENABLED (options
.creation_flags (),
195 ACE_Process_Options::NO_EXEC
))
196 ACE_NOTSUP_RETURN (ACE_INVALID_PID
);
198 if (options
.working_directory () != 0)
199 ACE_NOTSUP_RETURN (ACE_INVALID_PID
);
201 int saved_stdin
= ACE_STDIN
;
202 int saved_stdout
= ACE_STDOUT
;
203 int saved_stderr
= ACE_STDERR
;
204 // Save STD file descriptors and redirect
205 if (options
.get_stdin () != ACE_INVALID_HANDLE
) {
206 if ((saved_stdin
= ACE_OS::dup (ACE_STDIN
)) == -1 && errno
!= EBADF
)
207 ACE_OS::exit (errno
);
208 if (ACE_OS::dup2 (options
.get_stdin (), ACE_STDIN
) == -1)
209 ACE_OS::exit (errno
);
211 if (options
.get_stdout () != ACE_INVALID_HANDLE
) {
212 if ((saved_stdout
= ACE_OS::dup (ACE_STDOUT
)) == -1 && errno
!= EBADF
)
213 ACE_OS::exit (errno
);
214 if (ACE_OS::dup2 (options
.get_stdout (), ACE_STDOUT
) == -1)
215 ACE_OS::exit (errno
);
217 if (options
.get_stderr () != ACE_INVALID_HANDLE
) {
218 if ((saved_stderr
= ACE_OS::dup (ACE_STDERR
)) == -1 && errno
!= EBADF
)
219 ACE_OS::exit (errno
);
220 if (ACE_OS::dup2 (options
.get_stderr (), ACE_STDERR
) == -1)
221 ACE_OS::exit (errno
);
224 // Wide-char builds need narrow-char strings for commandline and
225 // environment variables.
226 # if defined (ACE_USES_WCHAR)
227 wchar_t * const *wargv
= options
.command_line_argv ();
229 for (vcount
= 0; wargv
[vcount
] != 0; ++vcount
)
231 char **procargv
= new char *[vcount
+ 1]; // Need 0 at the end
232 procargv
[vcount
] = 0;
233 for (i
= 0; i
< vcount
; ++i
)
234 procargv
[i
] = ACE_Wide_To_Ascii::convert (wargv
[i
]);
237 if (options
.inherit_environment ())
239 wargv
= options
.env_argv ();
240 for (vcount
= 0; wargv
[vcount
] != 0; ++vcount
)
242 procenv
= new char *[vcount
+ 1]; // Need 0 at the end
244 for (i
= 0; i
< vcount
; ++i
)
245 procenv
[i
] = ACE_Wide_To_Ascii::convert (wargv
[i
]);
248 const char **procargv
= const_cast<const char**> (options
.command_line_argv ());
249 const char **procenv
= const_cast<const char**> (options
.env_argv ());
250 # endif /* ACE_USES_WCHAR */
252 this->child_id_
= ::rtpSpawn (procargv
[0],
256 0x10000, // uStackSize
258 VX_FP_TASK
); // taskOptions
259 int my_errno_
= errno
;
260 if (this->child_id_
== ERROR
) {
261 // something went wrong
262 this->child_id_
= ACE_INVALID_PID
;
265 # if defined (ACE_USES_WCHAR)
268 # endif /* ACE_USES_WCHAR */
270 // restore STD file descriptors (if necessary)
271 if (options
.get_stdin () != ACE_INVALID_HANDLE
) {
272 if (saved_stdin
== -1)
273 ACE_OS::close (ACE_STDIN
);
275 ACE_OS::dup2 (saved_stdin
, ACE_STDIN
);
277 if (options
.get_stdout () != ACE_INVALID_HANDLE
) {
278 if (saved_stdout
== -1)
279 ACE_OS::close (ACE_STDOUT
);
281 ACE_OS::dup2 (saved_stdout
, ACE_STDOUT
);
283 if (options
.get_stderr () != ACE_INVALID_HANDLE
) {
284 if (saved_stderr
== -1)
285 ACE_OS::close (ACE_STDERR
);
287 ACE_OS::dup2 (saved_stderr
, ACE_STDERR
);
290 if (this->child_id_
== ACE_INVALID_PID
)
295 return this->child_id_
;
296 #else /* ACE_WIN32 */
297 // Fork the new process.
298 this->child_id_
= ACE::fork (options
.process_name (),
299 options
.avoid_zombies ());
301 if (this->child_id_
== 0)
303 # if !defined (ACE_LACKS_SETPGID)
304 // If we're the child and the options specified a non-default
305 // process group, try to set our pgid to it. This allows the
306 // <ACE_Process_Manager> to wait for processes by their
308 if (options
.getgroup () != ACE_INVALID_PID
309 && ACE_OS::setpgid (0,
310 options
.getgroup ()) < 0)
312 #if !defined (ACE_HAS_THREADS)
313 // We can't emit this log message because ACELIB_ERROR(), etc.
314 // will invoke async signal unsafe functions, which results
315 // in undefined behavior in threaded programs.
316 ACELIB_ERROR ((LM_ERROR
,
318 ACE_TEXT ("ACE_Process::spawn: setpgid failed.")));
321 # endif /* ACE_LACKS_SETPGID */
323 # if !defined (ACE_LACKS_SETREGID)
324 if (options
.getrgid () != (gid_t
) -1
325 || options
.getegid () != (gid_t
) -1)
326 if (ACE_OS::setregid (options
.getrgid (),
327 options
.getegid ()) == -1)
329 #if !defined (ACE_HAS_THREADS)
330 // We can't emit this log message because ACELIB_ERROR(), etc.
331 // will invoke async signal unsafe functions, which results
332 // in undefined behavior in threaded programs.
333 ACELIB_ERROR ((LM_ERROR
,
335 ACE_TEXT ("ACE_Process::spawn: setregid failed.")));
338 # endif /* ACE_LACKS_SETREGID */
340 # if !defined (ACE_LACKS_SETREUID)
341 // Set user and group id's.
342 if (options
.getruid () != (uid_t
) -1
343 || options
.geteuid () != (uid_t
) -1)
344 if (ACE_OS::setreuid (options
.getruid (),
345 options
.geteuid ()) == -1)
347 #if !defined (ACE_HAS_THREADS)
348 // We can't emit this log message because ACELIB_ERROR(), etc.
349 // will invoke async signal unsafe functions, which results
350 // in undefined behavior in threaded programs.
351 ACELIB_ERROR ((LM_ERROR
,
353 ACE_TEXT ("ACE_Process::spawn: setreuid failed.")));
356 # endif /* ACE_LACKS_SETREUID */
358 this->child (ACE_OS::getppid ());
360 else if (this->child_id_
!= -1)
361 this->parent (this->child_id_
);
363 // If we're not supposed to exec, return the process id.
364 if (ACE_BIT_ENABLED (options
.creation_flags (),
365 ACE_Process_Options::NO_EXEC
))
366 return this->child_id_
;
368 switch (this->child_id_
)
370 case static_cast<pid_t
>(-1):
372 return ACE_INVALID_PID
;
374 // Child process...exec the
376 if (options
.get_stdin () != ACE_INVALID_HANDLE
377 && ACE_OS::dup2 (options
.get_stdin (),
379 ACE_OS::exit (errno
);
380 else if (options
.get_stdout () != ACE_INVALID_HANDLE
381 && ACE_OS::dup2 (options
.get_stdout (),
383 ACE_OS::exit (errno
);
384 else if (options
.get_stderr () != ACE_INVALID_HANDLE
385 && ACE_OS::dup2 (options
.get_stderr (),
387 ACE_OS::exit (errno
);
389 // close down unneeded descriptors
390 ACE_OS::close (options
.get_stdin ());
391 ACE_OS::close (options
.get_stdout ());
392 ACE_OS::close (options
.get_stderr ());
393 if (!options
.handle_inheritance ())
395 // Set close-on-exec for all FDs except standard handles
396 for (int i
= ACE::max_handles () - 1; i
>= 0; i
--)
398 if (i
== ACE_STDIN
|| i
== ACE_STDOUT
|| i
== ACE_STDERR
)
400 ACE_OS::fcntl (i
, F_SETFD
, FD_CLOEXEC
);
404 // If we must, set the working directory for the child
406 if (options
.working_directory () != 0)
407 ACE_OS::chdir (options
.working_directory ());
408 // Should check for error here!
410 // Child process executes the command.
413 // Wide-char builds not on Windows need narrow-char strings for
414 // exec() and environment variables. Don't need to worry about
415 // releasing any of the converted string memory since this
416 // process will either exec() or exit() shortly.
417 # if defined (ACE_USES_WCHAR)
418 ACE_Wide_To_Ascii
n_procname (options
.process_name ());
419 const char *procname
= n_procname
.char_rep ();
421 wchar_t * const *wargv
= options
.command_line_argv ();
423 for (vcount
= 0; wargv
[vcount
] != 0; ++vcount
)
425 char **procargv
= new char *[vcount
+ 1]; // Need 0 at the end
426 procargv
[vcount
] = 0;
427 for (i
= 0; i
< vcount
; ++i
)
428 procargv
[i
] = ACE_Wide_To_Ascii::convert (wargv
[i
]);
430 wargv
= options
.env_argv ();
431 for (vcount
= 0; wargv
[vcount
] != 0; ++vcount
)
433 char **procenv
= new char *[vcount
+ 1]; // Need 0 at the end
435 for (i
= 0; i
< vcount
; ++i
)
436 procenv
[i
] = ACE_Wide_To_Ascii::convert (wargv
[i
]);
438 const char *procname
= options
.process_name ();
439 char *const *procargv
= options
.command_line_argv ();
440 char *const *procenv
= options
.env_argv ();
441 # endif /* ACE_USES_WCHAR */
443 if (options
.inherit_environment ())
445 // Add the new environment variables to the environment
446 // context of the context before doing an <execvp>.
447 for (size_t i
= 0; procenv
[i
] != 0; i
++)
448 if (ACE_OS::putenv (procenv
[i
]) != 0)
449 return ACE_INVALID_PID
;
451 // Now the forked process has both inherited variables and
452 // the user's supplied variables.
453 # ifdef ACE_LACKS_EXECVP
454 result
= ACE_OS::execv (procname
, procargv
);
456 result
= ACE_OS::execvp (procname
, procargv
);
461 result
= ACE_OS::execve (procname
, procargv
, procenv
);
465 // If the execv fails, this child needs to exit.
467 // Exit with the errno so that the calling process can
468 // catch this and figure out what went wrong.
469 ACE_OS::_exit (errno
);
471 // ... otherwise, this is never reached.
475 // Server process. The fork succeeded.
476 return this->child_id_
;
478 #endif /* ACE_WIN32 */
482 ACE_Process::parent (pid_t
)
488 ACE_Process::child (pid_t
)
494 ACE_Process::unmanage ()
500 ACE_Process::running () const
502 #if defined (ACE_WIN32)
505 BOOL result
= ::GetExitCodeProcess (this->gethandle (),
507 return result
&& code
== STILL_ACTIVE
;
509 if (ACE_INVALID_PID
== this->getpid ())
512 return ACE_OS::kill (this->getpid (),
515 #endif /* ACE_WIN32 */
519 ACE_Process::wait (const ACE_Time_Value
&tv
,
520 ACE_exitcode
*status
)
522 #if defined (ACE_WIN32)
523 // Don't try to get the process exit status if wait failed so we can
524 // keep the original error code intact.
525 switch (::WaitForSingleObject (process_info_
.hProcess
,
529 // The error status of <GetExitCodeProcess> is nonetheless not
530 // tested because we don't know how to return the value.
531 ::GetExitCodeProcess (process_info_
.hProcess
,
534 *status
= this->exit_code_
;
535 return this->getpid ();
540 ACE_OS::set_errno_to_last_error ();
543 #elif defined(ACE_LACKS_UNIX_SIGNALS)
544 if (tv
== ACE_Time_Value::zero
)
547 ACE_OS::waitpid (this->child_id_
,
551 *status
= this->exit_code_
;
556 if (tv
== ACE_Time_Value::max_time
)
557 # if defined (ACE_VXWORKS)
560 while ((retv
= this->wait (status
)) == ACE_INVALID_PID
&& errno
== EINTR
) ;
564 return this->wait (status
);
568 ACE_Time_Value
sleeptm (1); // 1 msec
569 if (sleeptm
> tv
) // if sleeptime > waittime
571 ACE_Time_Value
tmo (tv
); // Need one we can change
572 for (ACE_Countdown_Time
time_left (&tmo
); tmo
> ACE_Time_Value::zero
; time_left
.update ())
574 pid
= ACE_OS::waitpid (this->getpid (),
578 *status
= this->exit_code_
;
580 if (pid
> 0 || pid
== ACE_INVALID_PID
)
581 break; // Got a child or an error - all done
583 // pid 0, nothing is ready yet, so wait.
584 // Do a (very) short sleep (only this thread sleeps).
585 ACE_OS::sleep (sleeptm
);
589 #else /* !ACE_WIN32 && !ACE_LACKS_UNIX_SIGNALS */
590 if (tv
== ACE_Time_Value::zero
)
593 ACE_OS::waitpid (this->child_id_
,
597 *status
= this->exit_code_
;
602 if (tv
== ACE_Time_Value::max_time
)
603 return this->wait (status
);
605 // Need to wait but limited to specified time.
606 // Force generation of SIGCHLD, even though we don't want to
607 // catch it - just need it to interrupt the sleep below.
608 // If this object has a reactor set, assume it was given at
609 // open(), and there's already a SIGCHLD action set, so no
610 // action is needed here.
611 ACE_Sig_Action old_action
;
612 ACE_Sig_Handler_Ex sigchld_nop_ptr
= sigchld_nop
;
613 ACE_Sig_Action
do_sigchld (reinterpret_cast<ACE_SignalHandler
> (reinterpret_cast<void*> (sigchld_nop_ptr
)));
614 do_sigchld
.register_action (SIGCHLD
, &old_action
);
617 ACE_Time_Value
tmo (tv
); // Need one we can change
618 for (ACE_Countdown_Time
time_left (&tmo
); ; time_left
.update ())
620 pid
= ACE_OS::waitpid (this->getpid (),
624 *status
= this->exit_code_
;
626 if (pid
> 0 || pid
== ACE_INVALID_PID
)
627 break; // Got a child or an error - all done
629 // pid 0, nothing is ready yet, so wait.
630 // Do a sleep (only this thread sleeps) til something
631 // happens. This relies on SIGCHLD interrupting the sleep.
632 // If SIGCHLD isn't delivered, we'll need to do something
633 // with sigaction to force it.
634 if (-1 == ACE_OS::sleep (tmo
) && errno
== EINTR
)
641 // Restore the previous SIGCHLD action if it was changed.
642 old_action
.register_action (SIGCHLD
);
645 #endif /* ACE_WIN32 */
649 ACE_Process::close_dup_handles ()
651 if (this->dup_handles_
.num_set () > 0)
653 ACE_Handle_Set_Iterator
h_iter (this->dup_handles_
);
654 for (ACE_HANDLE h
= h_iter ();
655 h
!= ACE_INVALID_HANDLE
;
657 ACE_OS::closesocket (h
);
658 this->dup_handles_
.reset ();
664 ACE_Process::close_passed_handles ()
666 if (this->handles_passed_
.num_set () > 0)
668 ACE_Handle_Set_Iterator
h_iter (this->handles_passed_
);
669 for (ACE_HANDLE h
= h_iter ();
670 h
!= ACE_INVALID_HANDLE
;
672 ACE_OS::closesocket (h
);
673 this->handles_passed_
.reset ();
678 #if defined (ACE_WIN32) && \
679 defined (ACE_HAS_WCHAR) && !defined (ACE_USES_WCHAR)
681 ACE_Process::convert_env_buffer (const char* env
) const
683 // Total starts out at 1 due to the final block nul terminator
686 // Convert each individual character string to the equivalent wide
688 ACE_Vector
<wchar_t*> buffer
;
695 // Convert the char string to wchar_t
696 wchar_t* str
= ACE_Ascii_To_Wide::convert (env
+ start
);
698 // Add the length of the string plus the nul terminator
699 total
+= ACE_OS::strlen (str
) + 1;
701 // Save it and set up for the next string
702 buffer
.push_back (str
);
704 if (env
[start
] == '\0')
709 i
+= ACE_OS::strlen (env
+ i
);
713 // Copy each string into the buffer leaving a nul terminator between
714 // each string and adding a second nul terminator at the end
716 wchar_t* wenv
= new wchar_t[total
];
717 size_t length
= buffer
.size ();
718 for (i
= 0; i
< length
; ++i
)
720 ACE_OS::strcpy(wenv
+ start
, buffer
[i
]);
721 start
+= ACE_OS::strlen (buffer
[i
]) + 1;
729 ACE_Process_Options::ACE_Process_Options (bool inherit_environment
,
730 size_t command_line_buf_len
,
733 size_t max_cmdline_args
)
735 inherit_environment_ (inherit_environment
),
738 #if defined (ACE_WIN32)
739 environment_inherited_ (0),
740 process_attributes_ (0),
741 thread_attributes_ (0),
742 user_token_ (ACE_INVALID_HANDLE
),
743 close_user_token_ (false),
744 #else /* ACE_WIN32 */
745 stdin_ (ACE_INVALID_HANDLE
),
746 stdout_ (ACE_INVALID_HANDLE
),
747 stderr_ (ACE_INVALID_HANDLE
),
752 #endif /* ACE_WIN32 */
753 handle_inheritance_ (true),
754 set_handles_called_ (0),
755 environment_buf_index_ (0),
756 environment_argv_index_ (0),
757 environment_buf_ (0),
758 environment_buf_len_ (env_buf_len
),
759 max_environment_args_ (max_env_args
),
760 max_environ_argv_index_ (max_env_args
- 1),
761 command_line_argv_calculated_ (false),
762 command_line_buf_ (0),
763 command_line_copy_ (0),
764 command_line_buf_len_ (command_line_buf_len
),
765 max_command_line_args_ (max_cmdline_args
),
766 command_line_argv_ (0),
767 process_group_ (ACE_INVALID_PID
),
768 use_unicode_environment_ (false)
770 #if defined (ACE_HAS_ALLOC_HOOKS)
771 ACE_ALLOCATOR (command_line_buf_
,
772 static_cast<ACE_TCHAR
*>(ACE_Allocator::instance()->malloc(sizeof(ACE_TCHAR
) * command_line_buf_len
)));
774 ACE_NEW (command_line_buf_
,
775 ACE_TCHAR
[command_line_buf_len
]);
776 #endif /* ACE_HAS_ALLOC_HOOKS */
777 command_line_buf_
[0] = '\0';
778 process_name_
[0] = '\0';
780 working_directory_
[0] = '\0';
781 #if defined (ACE_HAS_ALLOC_HOOKS)
782 ACE_ALLOCATOR (environment_buf_
,
783 static_cast<ACE_TCHAR
*>(ACE_Allocator::instance()->malloc(sizeof(ACE_TCHAR
) * env_buf_len
)));
785 ACE_NEW (environment_buf_
,
786 ACE_TCHAR
[env_buf_len
]);
787 #endif /* ACE_HAS_ALLOC_HOOKS */
788 #if defined (ACE_HAS_ALLOC_HOOKS)
789 ACE_ALLOCATOR (environment_argv_
,
790 static_cast<ACE_TCHAR
**>(ACE_Allocator::instance()->malloc(sizeof(ACE_TCHAR
*) * max_env_args
)));
792 ACE_NEW (environment_argv_
,
793 ACE_TCHAR
*[max_env_args
]);
794 #endif /* ACE_HAS_ALLOC_HOOKS */
795 environment_buf_
[0] = '\0';
796 environment_argv_
[0] = 0;
797 #if defined (ACE_WIN32)
798 ACE_OS::memset ((void *) &this->startup_info_
,
800 sizeof this->startup_info_
);
801 this->startup_info_
.cb
= sizeof this->startup_info_
;
802 #endif /* ACE_WIN32 */
803 #if defined (ACE_HAS_ALLOC_HOOKS)
804 ACE_ALLOCATOR (command_line_argv_
,
805 static_cast<ACE_TCHAR
**>(ACE_Allocator::instance()->malloc(sizeof(ACE_TCHAR
*) * max_cmdline_args
)));
807 ACE_NEW (command_line_argv_
,
808 ACE_TCHAR
*[max_cmdline_args
]);
809 #endif /* ACE_HAS_ALLOC_HOOKS */
812 #if defined (ACE_WIN32)
814 ACE_Process_Options::inherit_environment ()
816 // Ensure only once execution.
817 if (environment_inherited_
)
819 environment_inherited_
= 1;
821 // Get the existing environment.
822 ACE_TCHAR
*existing_environment
= 0;
823 #if defined (ACE_HAS_WCHAR) && !defined (ACE_USES_WCHAR)
824 WCHAR
*existing_wide_env
= 0;
825 ACE_Vector
<char> temp_narrow_env
;
826 if (this->use_unicode_environment_
)
828 existing_wide_env
= ::GetEnvironmentStringsW ();
829 for (WCHAR
*iter
= existing_wide_env
; *iter
; ++iter
)
831 ACE_Wide_To_Ascii
wta (iter
);
832 size_t const len
= ACE_OS::strlen (wta
.char_rep ());
833 size_t const idx
= temp_narrow_env
.size ();
834 temp_narrow_env
.resize (idx
+ len
+ 1, 0);
835 ACE_OS::strncpy (&temp_narrow_env
[idx
], wta
.char_rep (), len
);
838 temp_narrow_env
.push_back (0);
839 existing_environment
= &temp_narrow_env
[0];
843 existing_environment
= ACE_OS::getenvstrings ();
847 while (existing_environment
[slot
] != '\0')
849 size_t const len
= ACE_OS::strlen (existing_environment
+ slot
);
851 // Add the string to our env buffer.
852 if (this->setenv_i (existing_environment
+ slot
, len
) == -1)
854 ACELIB_ERROR ((LM_ERROR
,
856 ACE_TEXT ("ACE_Process_Options::ACE_Process_Options")));
860 // Skip to the next word.
864 #if defined (ACE_HAS_WCHAR) && !defined (ACE_USES_WCHAR)
865 if (this->use_unicode_environment_
)
866 ::FreeEnvironmentStringsW (existing_wide_env
);
869 ACE_TEXT_FreeEnvironmentStrings (existing_environment
);
872 #else /* defined ACE_WIN32 */
875 ACE_Process_Options::env_argv ()
877 return environment_argv_
;
879 #endif /* ACE_WIN32 */
882 ACE_Process_Options::setenv (ACE_TCHAR
*envp
[])
887 if (this->setenv_i (envp
[i
], ACE_OS::strlen (envp
[i
])) == -1)
892 #if defined (ACE_WIN32)
893 if (inherit_environment_
)
894 this->inherit_environment ();
895 #endif /* ACE_WIN32 */
900 #ifndef ACE_LACKS_VA_FUNCTIONS
902 ACE_Process_Options::setenv (const ACE_TCHAR
*format
, ...)
904 ACE_TCHAR stack_buf
[DEFAULT_COMMAND_LINE_BUF_LEN
];
908 va_start (argp
, format
);
910 // Add the rest of the varargs.
911 int status
= ACE_OS::vsnprintf (stack_buf
, DEFAULT_COMMAND_LINE_BUF_LEN
, format
, argp
);
918 // Append the string to are environment buffer.
919 if (this->setenv_i (stack_buf
, ACE_OS::strlen (stack_buf
)) == -1)
922 #if defined (ACE_WIN32)
923 if (inherit_environment_
)
924 this->inherit_environment ();
925 #endif /* ACE_WIN32 */
931 ACE_Process_Options::setenv (const ACE_TCHAR
*variable_name
,
932 const ACE_TCHAR
*format
, ...)
934 // To address the potential buffer overflow,
935 // we now allocate the buffer on heap with a variable size.
936 size_t const buflen
= ACE_OS::strlen (variable_name
) + ACE_OS::strlen (format
) + 2;
937 ACE_TCHAR
*newformat
= 0;
938 ACE_NEW_RETURN (newformat
, ACE_TCHAR
[buflen
], -1);
939 std::unique_ptr
<ACE_TCHAR
[]> safe_newformat (newformat
);
941 // Add in the variable name.
942 ACE_OS::snprintf (safe_newformat
.get (), buflen
,
943 ACE_TEXT ("%") ACE_TEXT_PRIs
ACE_TEXT ("=%") ACE_TEXT_PRIs
,
944 variable_name
, format
);
946 // Add the rest of the varargs.
947 size_t tmp_buflen
= buflen
;
948 if (DEFAULT_COMMAND_LINE_BUF_LEN
> buflen
)
950 tmp_buflen
= DEFAULT_COMMAND_LINE_BUF_LEN
;
954 ACE_TCHAR
*stack_buf
= 0;
955 ACE_NEW_RETURN (stack_buf
, ACE_TCHAR
[tmp_buflen
], -1);
956 std::unique_ptr
<ACE_TCHAR
[]> safe_stack_buf (stack_buf
);
960 // Must restart varargs on each time through this loop,
962 va_start (argp
, format
);
964 retval
= ACE_OS::vsnprintf (safe_stack_buf
.get (), tmp_buflen
, safe_newformat
.get (), argp
);
969 if (retval
> ACE_Utils::truncate_cast
<int> (tmp_buflen
))
972 ACE_NEW_RETURN (stack_buf
, ACE_TCHAR
[tmp_buflen
], -1);
973 safe_stack_buf
.reset (stack_buf
);
982 // In case that vsnprintf is not supported,
983 // e.g., LynxOS and VxWorks 5, we have to
984 // fall back to vsprintf.
985 if (errno
== ENOTSUP
)
987 // ALERT: Since we have to use vsprintf here, there is still a chance that
988 // the stack_buf overflows, i.e., the length of the resulting string
989 // can still possibly go beyond the allocated stack_buf.
991 va_start (argp
, format
);
992 retval
= ACE_OS::vsprintf (safe_stack_buf
.get (), safe_newformat
.get (), argp
);
995 // vsprintf is failed.
999 // vsnprintf is failed.
1003 // Append the string to our environment buffer.
1004 if (this->setenv_i (safe_stack_buf
.get (),
1005 ACE_OS::strlen (safe_stack_buf
.get ())) == -1)
1008 #if defined (ACE_WIN32)
1009 if (inherit_environment_
)
1010 this->inherit_environment ();
1011 #endif /* ACE_WIN32 */
1015 #endif // ACE_LACKS_VA_FUNCTIONS
1018 ACE_Process_Options::setenv_i (ACE_TCHAR
*assignment
,
1021 // Add one for the null char.
1024 // If environment larger than allocated buffer return. Also check to
1025 // make sure we have enough room.
1026 if (environment_argv_index_
== max_environ_argv_index_
1027 || (len
+ environment_buf_index_
) >= environment_buf_len_
)
1030 // Copy the new environment string.
1031 ACE_OS::memcpy (environment_buf_
+ environment_buf_index_
,
1033 len
* sizeof (ACE_TCHAR
));
1035 // Update the argv array.
1036 environment_argv_
[environment_argv_index_
++] = environment_buf_
+ environment_buf_index_
;
1037 environment_argv_
[environment_argv_index_
] = 0;
1039 // Update our index.
1040 environment_buf_index_
+= len
;
1042 // Make sure the buffer is null-terminated.
1043 environment_buf_
[environment_buf_index_
] = '\0';
1048 ACE_Process_Options::set_handles (ACE_HANDLE std_in
,
1052 this->set_handles_called_
= 1;
1053 #if defined (ACE_WIN32)
1055 // Tell the new process to use our std handles.
1056 this->startup_info_
.dwFlags
= STARTF_USESTDHANDLES
;
1058 if (std_in
== ACE_INVALID_HANDLE
)
1060 if (std_out
== ACE_INVALID_HANDLE
)
1061 std_out
= ACE_STDOUT
;
1062 if (std_err
== ACE_INVALID_HANDLE
)
1063 std_err
= ACE_STDERR
;
1065 // STD handles may have value 0 (not ACE_INVALID_HANDLE) if there is no such
1066 // handle in the process. This was observed to occur for stdin in console
1067 // processes that were launched from services. In this case we need to make
1068 // sure not to return -1 from setting std_in so that we can process std_out
1072 if (!::DuplicateHandle (::GetCurrentProcess (),
1074 ::GetCurrentProcess (),
1075 &this->startup_info_
.hStdInput
,
1078 DUPLICATE_SAME_ACCESS
))
1084 if (!::DuplicateHandle (::GetCurrentProcess (),
1086 ::GetCurrentProcess (),
1087 &this->startup_info_
.hStdOutput
,
1090 DUPLICATE_SAME_ACCESS
))
1096 if (!::DuplicateHandle (::GetCurrentProcess (),
1098 ::GetCurrentProcess (),
1099 &this->startup_info_
.hStdError
,
1102 DUPLICATE_SAME_ACCESS
))
1105 #else /* ACE_WIN32 */
1106 this->stdin_
= ACE_OS::dup (std_in
);
1107 this->stdout_
= ACE_OS::dup (std_out
);
1108 this->stderr_
= ACE_OS::dup (std_err
);
1109 #endif /* ACE_WIN32 */
1111 return 0; // Success.
1116 ACE_Process_Options::release_handles ()
1118 if (set_handles_called_
)
1120 #if defined (ACE_WIN32)
1121 ACE_OS::close (startup_info_
.hStdInput
);
1122 ACE_OS::close (startup_info_
.hStdOutput
);
1123 ACE_OS::close (startup_info_
.hStdError
);
1124 #else /* ACE_WIN32 */
1125 ACE_OS::close (stdin_
);
1126 ACE_OS::close (stdout_
);
1127 ACE_OS::close (stderr_
);
1128 #endif /* ACE_WIN32 */
1129 set_handles_called_
= 0;
1133 ACE_Process_Options::~ACE_Process_Options ()
1136 #if defined (ACE_HAS_ALLOC_HOOKS)
1137 ACE_Allocator::instance()->free(environment_buf_
);
1138 ACE_Allocator::instance()->free(environment_argv_
);
1140 delete [] environment_buf_
;
1141 delete [] environment_argv_
;
1142 #endif /* ACE_HAS_ALLOC_HOOKS */
1143 #if defined (ACE_HAS_ALLOC_HOOKS)
1144 ACE_Allocator::instance()->free(command_line_buf_
);
1146 delete [] command_line_buf_
;
1147 #endif /* ACE_HAS_ALLOC_HOOKS */
1148 ACE::strdelete (command_line_copy_
);
1149 #if defined (ACE_HAS_ALLOC_HOOKS)
1150 ACE_Allocator::instance()->free(command_line_argv_
);
1152 delete [] command_line_argv_
;
1153 #endif /* ACE_HAS_ALLOC_HOOKS */
1155 #if defined (ACE_WIN32)
1156 if (user_token_
!= ACE_INVALID_HANDLE
&& close_user_token_
)
1158 ::CloseHandle(user_token_
);
1160 #endif /* ACE_WIN32 */
1164 ACE_Process_Options::command_line (const ACE_TCHAR
*const argv
[])
1170 ACE_OS::strcat (command_line_buf_
, argv
[i
]);
1174 // Check to see if the next argument will overflow the
1175 // command_line buffer.
1176 size_t const cur_len
=
1177 ACE_OS::strlen (command_line_buf_
)
1178 + ACE_OS::strlen (argv
[i
])
1181 if (cur_len
> command_line_buf_len_
)
1183 ACELIB_ERROR_RETURN ((LM_ERROR
,
1184 ACE_TEXT ("ACE_Process:command_line: ")
1185 ACE_TEXT ("command line is ")
1186 ACE_TEXT ("longer than %d\n"),
1187 command_line_buf_len_
),
1191 ACE_OS::strcat (command_line_buf_
, ACE_TEXT (" "));
1192 ACE_OS::strcat (command_line_buf_
, argv
[i
]);
1196 command_line_argv_calculated_
= false;
1197 return 0; // Success.
1200 #ifndef ACE_LACKS_VA_FUNCTIONS
1202 ACE_Process_Options::command_line (const ACE_TCHAR
*format
, ...)
1204 // Store all ... args in argp.
1206 va_start (argp
, format
);
1208 if (command_line_buf_len_
< 1)
1214 ACE_OS::vsnprintf (command_line_buf_
,
1215 command_line_buf_len_
,
1221 command_line_argv_calculated_
= false;
1225 #if defined (ACE_HAS_WCHAR)
1227 ACE_Process_Options::command_line (const ACE_ANTI_TCHAR
*format
, ...)
1229 ACE_ANTI_TCHAR
*anti_clb
= 0;
1230 ACE_NEW_RETURN (anti_clb
,
1231 ACE_ANTI_TCHAR
[this->command_line_buf_len_
],
1234 // Store all ... args in argp.
1236 va_start (argp
, format
);
1238 // sprintf the format and args into command_line_buf_.
1239 ACE_OS::vsnprintf (anti_clb
, this->command_line_buf_len_
, format
, argp
);
1244 ACE_OS::strcpy (this->command_line_buf_
,
1245 ACE_TEXT_ANTI_TO_TCHAR (anti_clb
));
1249 command_line_argv_calculated_
= false;
1252 #endif /* ACE_HAS_WCHAR */
1253 #endif // ACE_LACKS_VA_FUNCTIONS
1256 ACE_Process_Options::env_buf ()
1258 if (environment_buf_
[0] == '\0')
1261 return environment_buf_
;
1265 ACE_Process_Options::command_line_argv ()
1267 if (!command_line_argv_calculated_
)
1269 command_line_argv_calculated_
= true;
1271 // We need to free up any previous allocated memory first.
1272 ACE::strdelete (command_line_copy_
);
1274 // We need to make a dynamically allocated copy here since
1275 // ACE_Tokenizer modifies its arguments.
1276 command_line_copy_
= ACE::strnew (command_line_buf_
);
1277 // This tokenizer will replace all spaces with end-of-string
1278 // characters and will preserve text between "" and '' pairs.
1279 ACE_Tokenizer
parser (command_line_copy_
);
1280 parser
.delimiter_replace (' ', '\0');
1281 parser
.preserve_designators ('\"', '\"'); // "
1282 parser
.preserve_designators ('\'', '\'');
1286 command_line_argv_
[x
] = parser
.next ();
1287 while (command_line_argv_
[x
] != 0
1288 // subtract one for the ending zero.
1289 && ++x
< max_command_line_args_
- 1);
1291 command_line_argv_
[x
] = 0;
1294 return command_line_argv_
;
1297 // Cause the specified handle to be passed to a child process
1298 // when it's spawned.
1300 ACE_Process_Options::pass_handle (ACE_HANDLE h
)
1302 this->handles_passed_
.set_bit (h
);
1306 // Get a copy of the handles the ACE_Process_Options duplicated
1307 // for the spawned process.
1309 ACE_Process_Options::dup_handles (ACE_Handle_Set
&set
) const
1311 if (this->dup_handles_
.num_set () == 0)
1314 set
= this->dup_handles_
;
1318 // Get a copy of the handles passed to the spawned process. This
1319 // will be the set of handles previously passed to @arg pass_handle().
1321 ACE_Process_Options::passed_handles (ACE_Handle_Set
&set
) const
1323 if (this->handles_passed_
.num_set () == 0)
1326 set
= this->handles_passed_
;
1330 ACE_ALLOC_HOOK_DEFINE(ACE_Managed_Process
)
1333 ACE_Managed_Process::unmanage ()
1338 #if defined (ACE_WIN32)
1340 ACE_Process_Options::set_user_token (HANDLE token
, bool close_token
)
1342 if (user_token_
!= ACE_INVALID_HANDLE
&& close_user_token_
)
1344 ::CloseHandle(user_token_
);
1347 user_token_
= token
;
1348 close_user_token_
= close_token
;
1350 #endif /* ACE_WIN32 */
1352 ACE_END_VERSIONED_NAMESPACE_DECL