Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members   Related Pages  

Process.cpp

Go to the documentation of this file.
00001 #include "ace_pch.h"
00002 // $Id: Process.cpp,v 1.1.1.4.2.1 2003/03/13 19:44:22 chad Exp $
00003 
00004 #include "ace/OS.h"
00005 #include "ace/Process.h"
00006 #include "ace/ARGV.h"
00007 #include "ace/Signal.h"
00008 #include "ace/SString.h"
00009 #include "ace/Log_Msg.h"
00010 
00011 #if !defined (__ACE_INLINE__)
00012 #include "ace/Process.i"
00013 #endif /* __ACE_INLINE__ */
00014 
00015 ACE_RCSID (ace, Process, "$Id: Process.cpp,v 1.1.1.4.2.1 2003/03/13 19:44:22 chad Exp $")
00016 
00017 
00018 // This function acts as a signal handler for SIGCHLD. We don't really want
00019 // to do anything with the signal - it's just needed to interrupt a sleep.
00020 // See wait() for more info.
00021 #if !defined (ACE_WIN32)
00022 static void
00023 sigchld_nop (int, siginfo_t *, ucontext_t *)
00024 {
00025   return;
00026 }
00027 #endif /* ACE_WIN32 */
00028 
00029 
00030 
00031 ACE_Process::ACE_Process (void)
00032   :
00033 #if !defined (ACE_WIN32)
00034   child_id_ (ACE_INVALID_PID),
00035 #endif /* !defined (ACE_WIN32) */
00036   exit_code_ (0)
00037 {
00038 #if defined (ACE_WIN32)
00039   ACE_OS::memset ((void *) &this->process_info_,
00040                   0,
00041                   sizeof this->process_info_);
00042 #endif /* ACE_WIN32 */
00043 }
00044 
00045 ACE_Process::~ACE_Process (void)
00046 {
00047 #if defined (ACE_WIN32)
00048   // Free resources allocated in kernel.
00049   ACE_OS::close (this->process_info_.hThread);
00050   ACE_OS::close (this->process_info_.hProcess);
00051 #endif /* ACE_WIN32 */
00052   // If any handles were duplicated for the child process and
00053   // still not closed, get them now.
00054   this->close_dup_handles ();
00055 }
00056 
00057 int
00058 ACE_Process::prepare (ACE_Process_Options &)
00059 {
00060   return 0;
00061 }
00062 
00063 pid_t
00064 ACE_Process::spawn (ACE_Process_Options &options)
00065 {
00066   if (prepare (options) < 0)
00067     return ACE_INVALID_PID;
00068 
00069   // Stash the passed/duped handle sets away in this object for later
00070   // closing if needed or requested. At the same time, figure out which
00071   // ones to include in command line options if that's needed below.
00072   ACE_Handle_Set *set_p = 0;
00073   if (options.dup_handles (this->dup_handles_))
00074     set_p = &this->dup_handles_;
00075   else if (options.passed_handles (this->handles_passed_))
00076     set_p = &this->handles_passed_;
00077 
00078   // If we are going to end up running a new program (i.e. Win32, or
00079   // NO_EXEC option is set) then get any handles passed in the options,
00080   // and tack them onto the command line with +H <handle> options,
00081   // unless the command line runs out of space.
00082   // Note that we're using the knowledge that all the options, argvs, etc.
00083   // passed to the options are all sitting in the command_line_buf. Any
00084   // call to get the argv then splits them out. So, regardless of the
00085   // platform, tack them all onto the command line buf and take it
00086   // from there.
00087   if (set_p && !ACE_BIT_ENABLED (options.creation_flags (),
00088                                  ACE_Process_Options::NO_EXEC))
00089     {
00090       int maxlen = 0;
00091       ACE_TCHAR *cmd_line_buf = options.command_line_buf (&maxlen);
00092       size_t max_len = ACE_static_cast (size_t, maxlen);
00093       size_t curr_len = ACE_OS::strlen (cmd_line_buf);
00094       ACE_Handle_Set_Iterator h_iter (*set_p);
00095       // Because the length of the to-be-formatted +H option is not
00096       // known, and we don't have a snprintf, guess at the space
00097       // needed (20 chars), and use that as a limit.
00098       for (ACE_HANDLE h = h_iter ();
00099            h != ACE_INVALID_HANDLE && curr_len + 20 < max_len;
00100            h = h_iter ())
00101         {
00102           curr_len += ACE_OS::sprintf (&cmd_line_buf[curr_len],
00103                                        ACE_LIB_TEXT (" +H %d"),
00104                                        h);
00105         }
00106     }
00107 
00108 #if defined (ACE_HAS_WINCE)
00109   // Note that WinCE does not have process name included in the command line as argv[0]
00110   // like other OS environment.  Therefore, it is user's whole responsibility to call
00111   // 'ACE_Process_Options::process_name(const ACE_TCHAR *name)' to set the proper
00112   // process name (the execution file name with path if needed).
00113 
00114   BOOL fork_result =
00115     ACE_TEXT_CreateProcess (options.process_name(),
00116                             options.command_line_buf(),
00117                             options.get_process_attributes(),  // must be NULL in CE
00118                             options.get_thread_attributes(),   // must be NULL in CE
00119                             options.handle_inheritence(),      // must be false in CE
00120                             options.creation_flags(),          // must be NULL in CE
00121                             options.env_buf(),                 // environment variables, must be NULL in CE
00122                             options.working_directory(),       // must be NULL in CE
00123                             options.startup_info(),            // must be NULL in CE
00124                             &this->process_info_);
00125 
00126   if (fork_result)
00127     {
00128       parent (this->getpid ());
00129       return this->getpid ();
00130     }
00131   return ACE_INVALID_PID;
00132 
00133 #elif defined (ACE_WIN32)
00134   BOOL fork_result =
00135     ACE_TEXT_CreateProcess (0,
00136                             options.command_line_buf (),
00137                             options.get_process_attributes (),
00138                             options.get_thread_attributes (),
00139                             options.handle_inheritence (),
00140                             options.creation_flags (),
00141                             options.env_buf (), // environment variables
00142                             options.working_directory (),
00143                             options.startup_info (),
00144                             &this->process_info_);
00145 
00146   if (fork_result)
00147     {
00148       parent (this->getpid ());
00149       return this->getpid ();
00150     }
00151   return ACE_INVALID_PID;
00152 
00153 #elif defined (CHORUS)
00154   // This only works if we exec.  Chorus does not really support
00155   // forking.
00156   if (ACE_BIT_ENABLED (options.creation_flags (),
00157                        ACE_Process_Options::NO_EXEC))
00158     ACE_NOTSUP_RETURN (ACE_INVALID_PID);
00159 
00160   // These are all currently unsupported.
00161   if (options.get_stdin () != ACE_INVALID_HANDLE)
00162     ACE_NOTSUP_RETURN (ACE_INVALID_PID);
00163   if (options.get_stdout () != ACE_INVALID_HANDLE)
00164     ACE_NOTSUP_RETURN (ACE_INVALID_PID);
00165   if (options.get_stderr () != ACE_INVALID_HANDLE)
00166     ACE_NOTSUP_RETURN (ACE_INVALID_PID);
00167   if (options.working_directory () != 0)
00168     ACE_NOTSUP_RETURN (ACE_INVALID_PID);
00169 
00170   if (options.env_argv ()[0] == 0)
00171     // command-line args
00172     this->child_id_ = ACE_OS::execvp (options.process_name (),
00173                                       options.command_line_argv ());
00174   else
00175     {
00176       // Add the new environment variables to the environment context
00177       // of the context before doing an <execvp>.
00178       for (char *const *user_env = options.env_argv ();
00179            *user_env != 0;
00180            user_env++)
00181         if (ACE_OS::putenv (*user_env) != 0)
00182           return ACE_INVALID_PID;
00183 
00184       // Now the forked process has both inherited variables and the
00185       // user's supplied variables.
00186       this->child_id_ = ACE_OS::execvp (options.process_name (),
00187                                         options.command_line_argv ());
00188     }
00189 
00190   return this->child_id_;
00191 #else /* ACE_WIN32 */
00192   // Fork the new process.
00193   this->child_id_ = ACE::fork (options.process_name (),
00194                                options.avoid_zombies ());
00195 
00196   if (this->child_id_ == 0)
00197     {
00198 # if !defined (ACE_LACKS_SETPGID)
00199       // If we're the child and the options specified a non-default
00200       // process group, try to set our pgid to it.  This allows the
00201       // <ACE_Process_Manager> to wait for processes by their
00202       // process-group.
00203       if (options.getgroup () != ACE_INVALID_PID
00204           && ACE_OS::setpgid (0,
00205                               options.getgroup ()) < 0)
00206         ACE_ERROR ((LM_ERROR,
00207                     ACE_LIB_TEXT ("%p.\n"),
00208                     ACE_LIB_TEXT ("ACE_Process::spawn: setpgid failed.")));
00209 # endif /* ACE_LACKS_SETPGID */
00210 
00211 # if !defined (ACE_LACKS_SETREGID)
00212       if (options.getrgid () != (uid_t) -1
00213           || options.getegid () != (uid_t) -1)
00214         if (ACE_OS::setregid (options.getrgid (),
00215                               options.getegid ()) == -1)
00216           ACE_ERROR ((LM_ERROR,
00217                       ACE_LIB_TEXT ("%p.\n"),
00218                       ACE_LIB_TEXT ("ACE_Process::spawn: setregid failed.")));
00219 # endif /* ACE_LACKS_SETREGID */
00220 
00221 # if !defined (ACE_LACKS_SETREUID)
00222       // Set user and group id's.
00223       if (options.getruid () != (uid_t) -1
00224           || options.geteuid () != (uid_t) -1)
00225         if (ACE_OS::setreuid (options.getruid (),
00226                               options.geteuid ()) == -1)
00227           ACE_ERROR ((LM_ERROR,
00228                       ACE_LIB_TEXT ("%p.\n"),
00229                       ACE_LIB_TEXT ("ACE_Process::spawn: setreuid failed.")));
00230 # endif /* ACE_LACKS_SETREUID */
00231 
00232       this->child (ACE_OS::getppid ());
00233     }
00234   else if (this->child_id_ != -1)
00235     this->parent (this->child_id_);
00236 
00237   // If we're not supposed to exec, return the process id.
00238   if (ACE_BIT_ENABLED (options.creation_flags (),
00239                        ACE_Process_Options::NO_EXEC))
00240     return this->child_id_;
00241 
00242   switch (this->child_id_)
00243     {
00244     case -1:
00245       // Error.
00246       return ACE_INVALID_PID;
00247     case 0:
00248       // Child process...exec the
00249       {
00250         if (options.get_stdin () != ACE_INVALID_HANDLE
00251             && ACE_OS::dup2 (options.get_stdin (),
00252                              ACE_STDIN) == -1)
00253           ACE_OS::exit (errno);
00254         else if (options.get_stdout () != ACE_INVALID_HANDLE
00255                  && ACE_OS::dup2 (options.get_stdout (),
00256                                   ACE_STDOUT) == -1)
00257           ACE_OS::exit (errno);
00258         else if (options.get_stderr () != ACE_INVALID_HANDLE
00259                  && ACE_OS::dup2 (options.get_stderr (),
00260                                   ACE_STDERR) == -1)
00261           ACE_OS::exit (errno);
00262 
00263         // close down unneeded descriptors
00264         ACE_OS::close (options.get_stdin ());
00265         ACE_OS::close (options.get_stdout ());
00266         ACE_OS::close (options.get_stderr ());
00267 
00268         // If we must, set the working directory for the child
00269         // process.
00270         if (options.working_directory () != 0)
00271           ACE_OS::chdir (options.working_directory ());
00272         // Should check for error here!
00273 
00274         // Child process executes the command.
00275         int result = 0;
00276 
00277         if (options.inherit_environment ())
00278           {
00279             // Add the new environment variables to the environment
00280             // context of the context before doing an <execvp>.
00281             for (char *const *user_env = options.env_argv ();
00282                  *user_env != 0;
00283                  user_env++)
00284               if (ACE_OS::putenv (*user_env) != 0)
00285                 return ACE_INVALID_PID;
00286 
00287             // Now the forked process has both inherited variables and
00288             // the user's supplied variables.
00289             result = ACE_OS::execvp (options.process_name (),
00290                                      options.command_line_argv ());
00291           }
00292         else
00293           {
00294 #if defined (ghs)
00295             // GreenHills 1.8.8 (for VxWorks 5.3.x) can't compile this
00296             // code.  Processes aren't supported on VxWorks anyways.
00297             ACE_NOTSUP_RETURN (ACE_INVALID_PID);
00298 #else
00299             result = ACE_OS::execve (options.process_name (),
00300                                      options.command_line_argv (),
00301                                      options.env_argv ());
00302 # endif /* ghs */
00303           }
00304         if (result == -1)
00305           {
00306             // If the execv fails, this child needs to exit.
00307 
00308             // Exit with the errno so that the calling process can
00309             // catch this and figure out what went wrong.
00310             ACE_OS::_exit (errno);
00311           }
00312         // ... otherwise, this is never reached.
00313         return 0;
00314       }
00315     default:
00316       // Server process.  The fork succeeded.
00317       return this->child_id_;
00318     }
00319 #endif /* ACE_WIN32 */
00320 }
00321 
00322 void
00323 ACE_Process::parent (pid_t)
00324 {
00325   // nothing to do
00326 }
00327 
00328 void
00329 ACE_Process::child (pid_t)
00330 {
00331   // nothing to do
00332 }
00333 
00334 void
00335 ACE_Process::unmanage (void)
00336 {
00337   // nothing to do
00338 }
00339 
00340 int
00341 ACE_Process::running (void) const
00342 {
00343 #if defined (ACE_WIN32)
00344     DWORD code;
00345 
00346     BOOL result = ::GetExitCodeProcess (this->gethandle (),
00347                                         &code);
00348     return result && code == STILL_ACTIVE;
00349 #else
00350     return ACE_OS::kill (this->getpid (),
00351                          0) == 0
00352       || errno != ESRCH;
00353 #endif /* ACE_WIN32 */
00354 }
00355 
00356 pid_t
00357 ACE_Process::wait (const ACE_Time_Value &tv,
00358                    ACE_exitcode *status)
00359 {
00360 #if defined (ACE_WIN32)
00361   // Don't try to get the process exit status if wait failed so we can
00362   // keep the original error code intact.
00363   switch (::WaitForSingleObject (process_info_.hProcess,
00364                                  tv.msec ()))
00365     {
00366     case WAIT_OBJECT_0:
00367         // The error status of <GetExitCodeProcess> is nonetheless not
00368         // tested because we don't know how to return the value.
00369         ::GetExitCodeProcess (process_info_.hProcess,
00370                               &this->exit_code_);
00371       if (status != 0)
00372         *status = this->exit_code_;
00373       return this->getpid ();
00374     case WAIT_TIMEOUT:
00375       errno = ETIME;
00376       return 0;
00377     default:
00378       ACE_OS::set_errno_to_last_error ();
00379       return -1;
00380     }
00381 #else /* ACE_WIN32 */
00382   if (tv == ACE_Time_Value::zero)
00383     {
00384       pid_t retv =
00385         ACE_OS::waitpid (this->child_id_,
00386                          &this->exit_code_,
00387                          WNOHANG);
00388       if (status != 0)
00389         *status = this->exit_code_;
00390 
00391       return retv;
00392     }
00393 
00394   if (tv == ACE_Time_Value::max_time)
00395     return this->wait (status);
00396 
00397   // Need to wait but limited to specified time.
00398   // Force generation of SIGCHLD, even though we don't want to
00399   // catch it - just need it to interrupt the sleep below.
00400   // If this object has a reactor set, assume it was given at
00401   // open(), and there's already a SIGCHLD action set, so no
00402   // action is needed here.
00403   ACE_Sig_Action old_action;
00404   ACE_Sig_Action do_sigchld ((ACE_SignalHandler)sigchld_nop);
00405   do_sigchld.register_action (SIGCHLD, &old_action);
00406 
00407   pid_t pid;
00408   ACE_Time_Value tmo (tv);       // Need one we can change
00409   for (ACE_Countdown_Time time_left (&tmo); ; time_left.update ())
00410     {
00411       pid = ACE_OS::waitpid (this->getpid (),
00412                              &this->exit_code_,
00413                              WNOHANG);
00414       if (status != 0)
00415         *status = this->exit_code_;
00416 
00417       if (pid > 0 || pid == ACE_INVALID_PID)
00418         break;          // Got a child or an error - all done
00419 
00420       // pid 0, nothing is ready yet, so wait.
00421       // Do a sleep (only this thread sleeps) til something
00422       // happens. This relies on SIGCHLD interrupting the sleep.
00423       // If SIGCHLD isn't delivered, we'll need to do something
00424       // with sigaction to force it.
00425       if (-1 == ACE_OS::sleep (tmo) && errno == EINTR)
00426         continue;
00427       // Timed out
00428       pid = 0;
00429       break;
00430     }
00431 
00432   // Restore the previous SIGCHLD action if it was changed.
00433   old_action.register_action (SIGCHLD);
00434 
00435   return pid;
00436 #endif /* ACE_WIN32 */
00437 }
00438 
00439 void
00440 ACE_Process::close_dup_handles (void)
00441 {
00442   if (this->dup_handles_.num_set () > 0)
00443     {
00444       ACE_Handle_Set_Iterator h_iter (this->dup_handles_);
00445       for (ACE_HANDLE h = h_iter ();
00446            h != ACE_INVALID_HANDLE;
00447            h = h_iter ())
00448         ACE_OS::closesocket (h);
00449       this->dup_handles_.reset ();
00450     }
00451   return;
00452 }
00453 
00454 void
00455 ACE_Process::close_passed_handles (void)
00456 {
00457   if (this->handles_passed_.num_set () > 0)
00458     {
00459       ACE_Handle_Set_Iterator h_iter (this->handles_passed_);
00460       for (ACE_HANDLE h = h_iter ();
00461            h != ACE_INVALID_HANDLE;
00462            h = h_iter ())
00463         ACE_OS::closesocket (h);
00464       this->handles_passed_.reset ();
00465     }
00466   return;
00467 }
00468 
00469 
00470 ACE_Process_Options::ACE_Process_Options (int ie,
00471                                           int cobl,
00472                                           int ebl,
00473                                           int mea)
00474   :
00475 #if !defined (ACE_HAS_WINCE)
00476     inherit_environment_ (ie),
00477 #endif /* ACE_HAS_WINCE */
00478     creation_flags_ (0),
00479     avoid_zombies_ (0),
00480 #if !defined (ACE_HAS_WINCE)
00481 #if defined (ACE_WIN32)
00482     environment_inherited_ (0),
00483     handle_inheritence_ (TRUE),
00484     process_attributes_ (0),
00485     thread_attributes_ (0),
00486 #else /* ACE_WIN32 */
00487     stdin_ (ACE_INVALID_HANDLE),
00488     stdout_ (ACE_INVALID_HANDLE),
00489     stderr_ (ACE_INVALID_HANDLE),
00490     ruid_ ((uid_t) -1),
00491     euid_ ((uid_t) -1),
00492     rgid_ ((uid_t) -1),
00493     egid_ ((uid_t) -1),
00494 #endif /* ACE_WIN32 */
00495     set_handles_called_ (0),
00496     environment_buf_index_ (0),
00497     environment_argv_index_ (0),
00498     environment_buf_ (0),
00499     environment_buf_len_ (ebl),
00500     max_environment_args_ (mea),
00501     max_environ_argv_index_ (mea - 1),
00502 #endif /* !ACE_HAS_WINCE */
00503     command_line_argv_calculated_ (0),
00504     command_line_buf_ (0),
00505     command_line_buf_len_ (cobl),
00506     process_group_ (ACE_INVALID_PID)
00507 {
00508   ACE_NEW (command_line_buf_,
00509            ACE_TCHAR[cobl]);
00510   command_line_buf_[0] = '\0';
00511 
00512 #if !defined (ACE_HAS_WINCE)
00513   working_directory_[0] = '\0';
00514   ACE_NEW (environment_buf_,
00515            ACE_TCHAR[ebl]);
00516   ACE_NEW (environment_argv_,
00517            ACE_TCHAR *[mea]);
00518   environment_buf_[0] = '\0';
00519   environment_argv_[0] = 0;
00520   process_name_[0] = '\0';
00521 #if defined (ACE_WIN32)
00522   ACE_OS::memset ((void *) &this->startup_info_,
00523                   0,
00524                   sizeof this->startup_info_);
00525   this->startup_info_.cb = sizeof this->startup_info_;
00526 #endif /* ACE_WIN32 */
00527 #endif /* !ACE_HAS_WINCE */
00528 }
00529 
00530 #if !defined (ACE_HAS_WINCE)
00531 #if defined (ACE_WIN32)
00532 void
00533 ACE_Process_Options::inherit_environment (void)
00534 {
00535   // Ensure only once execution.
00536   if (environment_inherited_)
00537     return;
00538   environment_inherited_ = 1;
00539 
00540   // Get the existing environment.
00541   ACE_TCHAR *existing_environment = ACE_OS::getenvstrings ();
00542 
00543   size_t slot = 0;
00544 
00545   while (existing_environment[slot] != '\0')
00546     {
00547       size_t len = ACE_OS::strlen (existing_environment + slot);
00548 
00549       // Add the string to our env buffer.
00550       if (this->setenv_i (existing_environment + slot, len) == -1)
00551         {
00552           ACE_ERROR ((LM_ERROR,
00553                       ACE_LIB_TEXT ("%p.\n"),
00554                       ACE_LIB_TEXT ("ACE_Process_Options::ACE_Process_Options")));
00555           break;
00556         }
00557 
00558       // Skip to the next word.
00559       slot += len + 1;
00560     }
00561 
00562   ACE_TEXT_FreeEnvironmentStrings (existing_environment);
00563 }
00564 
00565 #else /* defined ACE_WIN32 */
00566 
00567 ACE_TCHAR * const *
00568 ACE_Process_Options::env_argv (void)
00569 {
00570   return environment_argv_;
00571 }
00572 
00573 #endif /* ACE_WIN32 */
00574 
00575 int
00576 ACE_Process_Options::setenv (ACE_TCHAR *envp[])
00577 {
00578   int i = 0;
00579   while (envp[i])
00580     {
00581       if (this->setenv_i (envp[i],
00582                           ACE_OS_String::strlen (envp[i])) == -1)
00583         return -1;
00584       i++;
00585     }
00586 
00587 #if defined (ACE_WIN32)
00588   if (inherit_environment_)
00589     this->inherit_environment ();
00590 #endif /* ACE_WIN32 */
00591 
00592   return 0;
00593 }
00594 
00595 int
00596 ACE_Process_Options::setenv (const ACE_TCHAR *format, ...)
00597 {
00598   ACE_TCHAR stack_buf[DEFAULT_COMMAND_LINE_BUF_LEN];
00599 
00600   // Start varargs.
00601   va_list argp;
00602   va_start (argp, format);
00603 
00604   // Add the rest of the varargs.
00605   ACE_OS::vsprintf (stack_buf,
00606                     format,
00607                     argp);
00608   // End varargs.
00609   va_end (argp);
00610 
00611   // Append the string to are environment buffer.
00612   if (this->setenv_i (stack_buf,
00613                       ACE_OS_String::strlen (stack_buf)) == -1)
00614     return -1;
00615 
00616 #if defined (ACE_WIN32)
00617   if (inherit_environment_)
00618     this->inherit_environment ();
00619 #endif /* ACE_WIN32 */
00620 
00621   return 0;
00622 }
00623 
00624 int
00625 ACE_Process_Options::setenv (const ACE_TCHAR *variable_name,
00626                              const ACE_TCHAR *format, ...)
00627 {
00628   ACE_TCHAR newformat[DEFAULT_COMMAND_LINE_BUF_LEN];
00629 
00630   // Add in the variable name.
00631   ACE_OS::sprintf (newformat,
00632                    ACE_LIB_TEXT ("%s=%s"),
00633                    variable_name,
00634                    format);
00635 
00636   ACE_TCHAR stack_buf[DEFAULT_COMMAND_LINE_BUF_LEN];
00637 
00638   // Start varargs.
00639   va_list argp;
00640   va_start (argp, format);
00641 
00642   // Add the rest of the varargs.
00643   ACE_OS::vsprintf (stack_buf, newformat, argp);
00644 
00645   // End varargs.
00646   va_end (argp);
00647 
00648   // Append the string to our environment buffer.
00649   if (this->setenv_i (stack_buf,
00650                       ACE_OS_String::strlen (stack_buf)) == -1)
00651     return -1;
00652 
00653 #if defined (ACE_WIN32)
00654   if (inherit_environment_)
00655     this->inherit_environment ();
00656 #endif /* ACE_WIN32 */
00657 
00658   return 0;
00659 }
00660 
00661 int
00662 ACE_Process_Options::setenv_i (ACE_TCHAR *assignment,
00663                                size_t len)
00664 {
00665   // Add one for the null char.
00666   len++;
00667 
00668   // If environment larger than allocated buffer return. Also check to
00669   // make sure we have enough room.
00670   if (environment_argv_index_ == max_environ_argv_index_
00671       || (len + environment_buf_index_) >= environment_buf_len_)
00672     return -1;
00673 
00674   // Copy the new environment string.
00675   ACE_OS::memcpy (environment_buf_ + environment_buf_index_,
00676                   assignment,
00677                   len * sizeof (ACE_TCHAR));
00678 
00679   // Update the argv array.
00680   environment_argv_[environment_argv_index_++] =
00681     environment_buf_ + environment_buf_index_;
00682   environment_argv_[environment_argv_index_] = 0;
00683 
00684   // Update our index.
00685   environment_buf_index_ += len;
00686 
00687   // Make sure the buffer is null-terminated.
00688   environment_buf_[environment_buf_index_] = '\0';
00689   return 0;
00690 }
00691 
00692 int
00693 ACE_Process_Options::set_handles (ACE_HANDLE std_in,
00694                                   ACE_HANDLE std_out,
00695                                   ACE_HANDLE std_err)
00696 {
00697   this->set_handles_called_ = 1;
00698 #if defined (ACE_WIN32)
00699 
00700   // Tell the new process to use our std handles.
00701   this->startup_info_.dwFlags = STARTF_USESTDHANDLES;
00702 
00703   if (std_in == ACE_INVALID_HANDLE)
00704     std_in = ACE_STDIN;
00705   if (std_out == ACE_INVALID_HANDLE)
00706     std_out = ACE_STDOUT;
00707   if (std_err == ACE_INVALID_HANDLE)
00708     std_err = ACE_STDERR;
00709 
00710   if (!::DuplicateHandle (::GetCurrentProcess (),
00711                           std_in,
00712                           ::GetCurrentProcess (),
00713                           &this->startup_info_.hStdInput,
00714                           0,
00715                           TRUE,
00716                           DUPLICATE_SAME_ACCESS))
00717     return -1;
00718 
00719   if (!::DuplicateHandle (::GetCurrentProcess (),
00720                           std_out,
00721                           ::GetCurrentProcess (),
00722                           &this->startup_info_.hStdOutput,
00723                           0,
00724                           TRUE,
00725                           DUPLICATE_SAME_ACCESS))
00726     return -1;
00727 
00728   if (!::DuplicateHandle (::GetCurrentProcess (),
00729                           std_err,
00730                           ::GetCurrentProcess (),
00731                           &this->startup_info_.hStdError,
00732                           0,
00733                           TRUE,
00734                           DUPLICATE_SAME_ACCESS))
00735     return -1;
00736 #else /* ACE_WIN32 */
00737   this->stdin_ = ACE_OS::dup (std_in);
00738   this->stdout_ = ACE_OS::dup (std_out);
00739   this->stderr_ = ACE_OS::dup (std_err);
00740 #endif /* ACE_WIN32 */
00741 
00742   return 0; // Success.
00743 }
00744 
00745 
00746 void
00747 ACE_Process_Options::release_handles ()
00748 {
00749   if (set_handles_called_)
00750     {
00751 #if defined (ACE_WIN32)
00752       ACE_OS::close (startup_info_.hStdInput);
00753       ACE_OS::close (startup_info_.hStdOutput);
00754       ACE_OS::close (startup_info_.hStdError);
00755 #else /* ACE_WIN32 */
00756       ACE_OS::close (stdin_);
00757       ACE_OS::close (stdout_);
00758       ACE_OS::close (stderr_);
00759 #endif /* ACE_WIN32 */
00760       set_handles_called_ = 0;
00761     }
00762 }
00763 #endif /* !ACE_HAS_WINCE */
00764 
00765 
00766 ACE_Process_Options::~ACE_Process_Options (void)
00767 {
00768 #if !defined (ACE_HAS_WINCE)
00769   release_handles();
00770   delete [] environment_buf_;
00771   delete [] environment_argv_;
00772 #endif /* !ACE_HAS_WINCE */
00773   delete [] command_line_buf_;
00774 }
00775 
00776 int
00777 ACE_Process_Options::command_line (const ACE_TCHAR *const argv[])
00778 {
00779   // @@ Factor out the code between this
00780   int i = 0;
00781 
00782   if (argv[i])
00783     {
00784       ACE_OS::strcat (command_line_buf_, argv[i]);
00785       while (argv[++i])
00786         {
00787           ACE_OS::strcat (command_line_buf_,
00788                           ACE_LIB_TEXT (" "));
00789           ACE_OS::strcat (command_line_buf_,
00790                           argv[i]);
00791         }
00792     }
00793 
00794   command_line_argv_calculated_ = 0;
00795   return 0; // Success.
00796 }
00797 
00798 int
00799 ACE_Process_Options::command_line (const ACE_TCHAR *format, ...)
00800 {
00801   // Store all ... args in argp.
00802   va_list argp;
00803   va_start (argp, format);
00804 
00805   // sprintf the format and args into command_line_buf__.
00806   ACE_OS::vsprintf (command_line_buf_,
00807                     format,
00808                     argp);
00809 
00810   // Useless macro.
00811   va_end (argp);
00812 
00813   command_line_argv_calculated_ = 0;
00814   return 0;
00815 }
00816 
00817 #if defined (ACE_HAS_WCHAR) && !defined (ACE_HAS_WINCE)
00818 /**
00819  * @note Not available on Windows CE because it doesn't have a char version of
00820  * vsprintf.
00821  */
00822 int
00823 ACE_Process_Options::command_line (const ACE_ANTI_TCHAR *format, ...)
00824 {
00825   ACE_ANTI_TCHAR *anti_clb;
00826   ACE_NEW_RETURN (anti_clb,
00827                   ACE_ANTI_TCHAR[this->command_line_buf_len_],
00828                   -1);
00829 
00830   // Store all ... args in argp.
00831   va_list argp;
00832   va_start (argp, format);
00833 
00834   // sprintf the format and args into command_line_buf_.
00835   ACE_OS::vsprintf (anti_clb,
00836                     format,
00837                     argp);
00838 
00839   // Useless macro.
00840   va_end (argp);
00841 
00842   ACE_OS::strcpy (this->command_line_buf_,
00843                   ACE_TEXT_ANTI_TO_TCHAR (anti_clb));
00844 
00845   delete [] anti_clb;
00846 
00847   command_line_argv_calculated_ = 0;
00848   return 0;
00849 }
00850 #endif /* ACE_HAS_WCHAR && !ACE_HAS_WINCE */
00851 
00852 ACE_TCHAR *
00853 ACE_Process_Options::env_buf (void)
00854 {
00855 #if !defined (ACE_HAS_WINCE)
00856   if (environment_buf_[0] == '\0')
00857     return 0;
00858   else
00859     return environment_buf_;
00860 #else
00861   return 0;
00862 #endif /* !ACE_HAS_WINCE */
00863 }
00864 
00865 ACE_TCHAR * const *
00866 ACE_Process_Options::command_line_argv (void)
00867 {
00868   if (command_line_argv_calculated_ == 0)
00869     {
00870       command_line_argv_calculated_ = 1;
00871 
00872       // This tokenizer will replace all spaces with end-of-string
00873       // characters and will preserve text between "" and '' pairs.
00874       ACE_Tokenizer parser (command_line_buf_);
00875       parser.delimiter_replace (' ', '\0');
00876       parser.preserve_designators ('\"', '\"'); // "
00877       parser.preserve_designators ('\'', '\'');
00878 
00879       int x = 0;
00880       do
00881         command_line_argv_[x] = parser.next ();
00882       while (command_line_argv_[x] != 0
00883              // substract one for the ending zero.
00884              && ++x < MAX_COMMAND_LINE_OPTIONS - 1);
00885 
00886       command_line_argv_[x] = 0;
00887     }
00888 
00889   return command_line_argv_;
00890 }
00891 
00892 
00893 // Cause the specified handle to be passed to a child process
00894 // when it's spawned.
00895 int
00896 ACE_Process_Options::pass_handle (ACE_HANDLE h)
00897 {
00898 # if defined (ACE_WIN32)
00899 #  if defined (ACE_HAS_WINCE)
00900   ACE_NOTSUP_RETURN (-1);
00901 #  else
00902 
00903   // This is oriented towards socket handles... may need some adjustment
00904   // for non-sockets.
00905   // This is all based on an MSDN article:
00906   // http://support.microsoft.com/support/kb/articles/Q150/5/23.asp
00907   // If on Win95/98, the handle needs to be duplicated for the to-be-spawned
00908   // process. On WinNT, they get inherited by the child process automatically.
00909   // If the handle is duplicated, remember the duplicate so it can be
00910   // closed later. Can't be closed now, or the child won't get it.
00911   OSVERSIONINFO osvi;
00912   ZeroMemory (&osvi, sizeof (osvi));
00913   osvi.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
00914   // If this is Win95/98 or we can't tell, duplicate the handle.
00915   if (!GetVersionEx (&osvi) || osvi.dwPlatformId != VER_PLATFORM_WIN32_NT)
00916     {
00917       HANDLE dup_handle;
00918       if (!DuplicateHandle (GetCurrentProcess (),
00919                             ACE_static_cast (HANDLE, h),
00920                             GetCurrentProcess (),
00921                             &dup_handle,
00922                             0,
00923                             TRUE,   // Inheritable
00924                             DUPLICATE_SAME_ACCESS))
00925         return -1;
00926       dup_handles_.set_bit (ACE_static_cast (ACE_HANDLE, dup_handle));
00927     }
00928 #  endif /* ACE_HAS_WINCE */
00929 #endif /* ACE_WIN32 */
00930 
00931   this->handles_passed_.set_bit (h);
00932 
00933   return 0;
00934 }
00935 
00936 // Get a copy of the handles the ACE_Process_Options duplicated
00937 // for the spawned process.
00938 int
00939 ACE_Process_Options::dup_handles (ACE_Handle_Set &set) const
00940 {
00941   if (this->dup_handles_.num_set () == 0)
00942     return 0;
00943   set.reset ();
00944   set = this->dup_handles_;
00945   return 1;
00946 }
00947 
00948 // Get a copy of the handles passed to the spawned process. This
00949 // will be the set of handles previously passed to @arg pass_handle().
00950 int
00951 ACE_Process_Options::passed_handles (ACE_Handle_Set &set) const
00952 {
00953   if (this->handles_passed_.num_set () == 0)
00954     return 0;
00955   set.reset ();
00956   set = this->handles_passed_;
00957   return 1;
00958 }
00959 
00960 ACE_Managed_Process::ACE_Managed_Process (void)
00961 {
00962 }
00963 
00964 ACE_Managed_Process::~ACE_Managed_Process (void)
00965 {
00966 }

Generated on Mon Jun 16 11:20:54 2003 for ACE by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002