LCOV - code coverage report
Current view: top level - okssystem/src - Executable.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 0.0 % 327 0
Test Date: 2026-10-11 15:05:20 Functions: 0.0 % 18 0

            Line data    Source code
       1              : // DUNE DAQ modification notice:
       2              : // This file has been modified from the original ATLAS system source for the DUNE DAQ project.
       3              : // Fork baseline commit: system-00-00-20 (2020-09-25).
       4              : // Renamed since fork: yes (from src/Executable.cxx to src/Executable.cpp).
       5              : 
       6              : /*
       7              :  *  Executable.cxx
       8              :  *  ers
       9              :  *
      10              :  *  Created by Matthias Wiesmann on 06.01.05.
      11              :  *  Copyright 2005 CERN. All rights reserved.
      12              :  *
      13              :  */
      14              : 
      15              : #include <cstdio>
      16              : #include <cstdlib>
      17              : #include <fcntl.h>
      18              : #include <iostream>
      19              : #include <pthread.h>
      20              : #include <signal.h>
      21              : #include <sstream>
      22              : #include <sys/stat.h>
      23              : #include <sys/types.h>
      24              : #include <sys/uio.h>
      25              : #include <unistd.h>
      26              : 
      27              : #include "ers/Assertion.hpp"
      28              : #include "ers/ers.hpp"
      29              : 
      30              : #include "okssystem/Descriptor.hpp"
      31              : #include "okssystem/Environment.hpp"
      32              : #include "okssystem/Executable.hpp"
      33              : #include "okssystem/Process.hpp"
      34              : #include "okssystem/exceptions.hpp"
      35              : 
      36              : const char* const OksSystem::Executable::SHELL_COMMAND = "/bin/sh";
      37              : const char* const OksSystem::Executable::SHELL_COMMAND_PARAM = "-c";
      38              : 
      39              : /** This method is a safe replacement for the okssystem function.
      40              :  * It basically offers the same functionality with better error handling.
      41              :  * The command is executed in a shell via \c /bin/sh \c -c.
      42              :  * If the command is successfull (return value 0), this method returns the resulting string.
      43              :  * If the command fails, this method throws an exception of type \c okssystem::ExecutionIssue.
      44              :  * This exception contains the return code and the content of stderr.
      45              :  * \param command the command to execute
      46              :  * \return the content of the stdout stream for the executed command
      47              :  * \see pipe_in()
      48              :  */
      49              : 
      50              : std::string
      51            0 : OksSystem::Executable::okssystem(const std::string& command)
      52              : {
      53            0 :   OksSystem::Executable shell(SHELL_COMMAND);
      54            0 :   std::vector<std::string> params;
      55            0 :   params.push_back(SHELL_COMMAND_PARAM);
      56            0 :   params.push_back(command);
      57            0 :   return shell.pipe_in(params);
      58            0 : } // std::string
      59              : 
      60            0 : OksSystem::Executable::Executable(const OksSystem::File& file)
      61            0 :   : OksSystem::File(file)
      62              : {
      63            0 : }
      64            0 : OksSystem::Executable::Executable(const char* filename)
      65            0 :   : OksSystem::File(filename)
      66              : {
      67            0 : }
      68            0 : OksSystem::Executable::Executable(const std::string& filename)
      69            0 :   : OksSystem::File(filename)
      70              : {
      71            0 : }
      72            0 : OksSystem::Executable::~Executable() {}
      73              : 
      74              : /** Core execution method.
      75              :  * This method assumes the datastructures have been setup correctly for \c execv.
      76              :  * It basically adds some error handling to \c execv
      77              :  * \param argv array of arguments, with name of the executable in first position
      78              :  * \note this method should not be called directly
      79              :  */
      80              : 
      81              : void
      82            0 : OksSystem::Executable::exec(char** argv) const
      83              : {
      84            0 :   ERS_PRECONDITION(argv);
      85            0 :   ERS_PRECONDITION(argv[0]);
      86            0 :   const int status = ::execv(argv[0], argv);
      87            0 :   throw OksSystem::ExecutionIssue(ERS_HERE, errno, argv[0], status);
      88              : } // exec
      89              : 
      90              : /** Core execution method.
      91              :  * This method assumes the datastructures have been setup correctly for \c execve.
      92              :  * It basically adds some error handling to \c execve.
      93              :  * Look at the \c execve man pages for details.
      94              :  * \param argv array of arguments, with name of the executable in first position
      95              :  * \param env array containing the environment the process will be started with
      96              :  */
      97              : void
      98            0 : OksSystem::Executable::exec(char** const argv, char** const env) const
      99              : {
     100            0 :   ERS_PRECONDITION(argv);
     101            0 :   ERS_PRECONDITION(argv[0]);
     102            0 :   ERS_PRECONDITION(env);
     103            0 :   const int status = ::execve(argv[0], argv, env);
     104            0 :   throw OksSystem::ExecutionIssue(ERS_HERE, errno, argv[0], status);
     105              : }
     106              : 
     107              : /** Simple execution method.
     108              :  * This methods converts the vector of strings into the correct data structures for \c execv.
     109              :  * The \c argv structure is allocated dynamically and new string copied into it.
     110              :  */
     111              : 
     112              : void
     113            0 : OksSystem::Executable::exec(const param_collection& params) const
     114              : {
     115            0 :   const int argc = params.size(); // number of parameters
     116            0 :   const int argclen = argc + 2;   // size of array parameters + program name + null pointer
     117            0 :   char** argv = (char**)calloc(sizeof(char*), argclen);
     118            0 :   OKSSYSTEM_ALLOC_CHECK(argv, sizeof(char*) * argclen);
     119            0 :   const char* name = *this;
     120            0 :   argv[0] = strdup(name);
     121            0 :   OKSSYSTEM_ALLOC_CHECK(argv[0], strlen(name));
     122            0 :   for (int i = 0; i < argc; i++) {
     123            0 :     argv[i + 1] = strdup(params[i].c_str());
     124              :   } // loop over args
     125            0 :   argv[argc + 1] = 0;
     126            0 :   try {
     127            0 :     exec(argv);
     128            0 :   } catch (OksSystem::ExecutionIssue& ex) {
     129            0 :     for (int i = 0; argv[i] != 0; i++) {
     130            0 :       free(argv[i]);
     131              :     } // for
     132            0 :     free(argv);
     133            0 :     throw;
     134            0 :   } catch (ers::Issue& issue) { // there was a problem so we deallocate the argc array.
     135            0 :     for (int i = 0; argv[i] != 0; i++) {
     136            0 :       free(argv[i]);
     137              :     } // for
     138            0 :     free(argv);
     139            0 :     throw;
     140            0 :   } // catch
     141            0 : } // exec
     142              : 
     143              : /** This execution method calls the 'execve' function executing the
     144              :  * \param params the parameters to use when launching the executable
     145              :  * \param envs table of the environnement variables set for the executable
     146              :  */
     147              : 
     148              : void
     149            0 : OksSystem::Executable::exec(const param_collection& params, const env_collection& envs) const
     150              : {
     151              : 
     152              :   // Elaborate the environment
     153            0 :   const unsigned int envArraySize = envs.size() + 1; // The last elements must be NULL
     154            0 :   char** const env = new char*[envArraySize];
     155              : 
     156            0 :   {
     157            0 :     const env_collection::const_iterator b = envs.begin();
     158            0 :     const env_collection::const_iterator e = envs.end();
     159            0 :     env_collection::const_iterator it;
     160              : 
     161            0 :     unsigned int counter = 0;
     162            0 :     for (it = b; it != e; ++it) {
     163            0 :       const std::string entry = it->first + "=" + it->second;
     164            0 :       env[counter] = new char[entry.size() + 1]; // Add the NULL terminator
     165            0 :       ::strcpy(env[counter], entry.c_str());
     166            0 :       ++counter;
     167            0 :     }
     168              : 
     169            0 :     env[envArraySize - 1] = (char*)0;
     170              :   }
     171              : 
     172              :   // Elaborate the paramenters
     173            0 :   const unsigned int paramArraySize = params.size() + 2; // Add the executable name and the NULL terminator
     174            0 :   char** const par = new char*[paramArraySize];
     175              : 
     176            0 :   {
     177            0 :     const std::string& binName = this->full_name();
     178            0 :     par[0] = new char[binName.size() + 1]; // Add the NULL terminator
     179            0 :     ::strcpy(par[0], binName.c_str());
     180              : 
     181            0 :     const param_collection::const_iterator b = params.begin();
     182            0 :     const param_collection::const_iterator e = params.end();
     183            0 :     param_collection::const_iterator it;
     184              : 
     185            0 :     unsigned int counter = 1;
     186            0 :     for (it = b; it != e; ++it) {
     187            0 :       const std::string& value = *it;
     188            0 :       par[counter] = new char[value.size() + 1]; // Add the NULL terminator
     189            0 :       ::strcpy(par[counter], value.c_str());
     190            0 :       ++counter;
     191              :     }
     192              : 
     193            0 :     par[paramArraySize - 1] = (char*)0;
     194              :   }
     195              : 
     196            0 :   try {
     197            0 :     exec(par, env);
     198            0 :   } catch (OksSystem::ExecutionIssue& ex) {
     199              :     // if we are here it means that the exec call failed!!!
     200              :     // Free the allocated memory
     201            0 :     for (unsigned int i = 0; i < envArraySize; ++i) {
     202            0 :       delete[] env[i];
     203              :     }
     204            0 :     delete[] env;
     205              : 
     206            0 :     for (unsigned int i = 0; i < paramArraySize; ++i) {
     207            0 :       delete[] par[i];
     208              :     }
     209            0 :     delete[] par;
     210              : 
     211              :     // Re-throw the exception
     212            0 :     throw ex;
     213            0 :   }
     214            0 : }
     215              : 
     216              : /** This method starts the executable in another process using \c fork
     217              :  * \param params the parameters to use when launching the executable
     218              :  * \return A process object representing the started process
     219              :  */
     220              : 
     221              : OksSystem::Process
     222            0 : OksSystem::Executable::start(const param_collection& params) const
     223              : {
     224              : 
     225              :   // Block all signals before fork()
     226            0 :   sigset_t new_set;
     227            0 :   sigset_t old_set;
     228            0 :   sigfillset(&new_set);
     229            0 :   pthread_sigmask(SIG_SETMASK, &new_set, &old_set);
     230              : 
     231            0 :   const pid_t child_id = fork();
     232            0 :   if (0 == child_id) { // we are the child
     233              : 
     234              :     // Put some signals to their default
     235            0 :     signal(SIGTERM, SIG_DFL);
     236            0 :     signal(SIGINT, SIG_DFL);
     237              : 
     238              :     // Restore the original signal mask in child
     239            0 :     pthread_sigmask(SIG_SETMASK, &old_set, NULL);
     240              : 
     241            0 :     try {
     242            0 :       exec(params);
     243            0 :     } catch (OksSystem::ExecutionIssue& ex) {
     244            0 :       ers::warning(ex);
     245            0 :       _exit(EXIT_FAILURE);
     246            0 :     } catch (ers::Issue& ex) {
     247            0 :       ers::warning(ex);
     248            0 :       _exit(EXIT_FAILURE);
     249            0 :     }
     250              : 
     251              :   } // we are the child
     252            0 :   if (child_id > 0) { // we are the parent
     253              : 
     254              :     // Restore the original signal mask in parent
     255            0 :     pthread_sigmask(SIG_SETMASK, &old_set, NULL);
     256              : 
     257            0 :     return Process(child_id, to_string(params));
     258              : 
     259              :   } // we are the parent
     260              : 
     261              :   // Restore the original signal mask in case of a fork() failure
     262            0 :   pthread_sigmask(SIG_SETMASK, &old_set, NULL);
     263              : 
     264            0 :   throw OksSystem::OksSystemCallIssue(ERS_HERE, errno, "fork", ""); // We are screwed up
     265              : } // start
     266              : 
     267              : /** This method starts the executable in another process using \c fork. The parent will not wait on the child
     268              :  * termination.
     269              :  * \param params the parameters to use when launching the executable
     270              :  * \return A process object representing the started process
     271              :  */
     272              : 
     273              : OksSystem::Process
     274            0 : OksSystem::Executable::start_and_forget(const param_collection& params) const
     275              : {
     276              : 
     277              :   // Block all signals before fork()
     278            0 :   sigset_t new_set;
     279            0 :   sigset_t old_set;
     280            0 :   sigfillset(&new_set);
     281            0 :   pthread_sigmask(SIG_SETMASK, &new_set, &old_set);
     282              : 
     283            0 :   signal(SIGCLD, SIG_IGN); /* now I don't have to wait()! */
     284              : 
     285            0 :   const pid_t child_id = fork();
     286            0 :   if (0 == child_id) { // we are the child
     287              : 
     288              :     // Put some signals to their default
     289            0 :     signal(SIGTERM, SIG_DFL);
     290            0 :     signal(SIGINT, SIG_DFL);
     291            0 :     signal(SIGCLD, SIG_DFL); /* Restore default SIGCLD handling in the child process */
     292              : 
     293              :     // Restore the original signal mask in child
     294            0 :     pthread_sigmask(SIG_SETMASK, &old_set, NULL);
     295              : 
     296            0 :     try {
     297            0 :       exec(params);
     298            0 :     } catch (OksSystem::ExecutionIssue& ex) {
     299            0 :       ers::warning(ex);
     300            0 :       _exit(EXIT_FAILURE);
     301            0 :     } catch (ers::Issue& ex) {
     302            0 :       ers::warning(ex);
     303            0 :       _exit(EXIT_FAILURE);
     304            0 :     }
     305              : 
     306              :   } // we are the child
     307            0 :   if (child_id > 0) { // we are the parent
     308              : 
     309              :     // Restore the original signal mask in parent
     310            0 :     pthread_sigmask(SIG_SETMASK, &old_set, NULL);
     311              : 
     312            0 :     return Process(child_id, to_string(params));
     313              :   } // we are the parent
     314              : 
     315              :   // Restore the original signal mask in case of a fork() failure
     316            0 :   pthread_sigmask(SIG_SETMASK, &old_set, NULL);
     317              : 
     318            0 :   throw OksSystem::OksSystemCallIssue(ERS_HERE, errno, "fork", ""); // We are screwed up
     319              : } // start
     320              : 
     321              : /** Copies the content of a file descriptor into a STL stream
     322              :  * \param fd the source file descriptor
     323              :  * \param target the target stream
     324              :  * \note a more efficient version could use the underlying STL buffer
     325              :  */
     326              : 
     327              : void
     328            0 : OksSystem::Executable::copy_fd(int fd, std::ostream& target)
     329              : {
     330            0 :   while (true) {
     331            0 :     char buffer[256];
     332            0 :     long status = read(fd, buffer, sizeof(buffer));
     333            0 :     if (status <= 0)
     334            0 :       return;
     335            0 :     ERS_ASSERT(status <= (long)sizeof(buffer));
     336            0 :     for (int i = 0; i < status; i++) {
     337            0 :       target << (char)buffer[i];
     338              :     } // for
     339            0 :   } // while
     340              : } // copy_fd
     341              : 
     342              : /** \overload */
     343              : 
     344              : std::string
     345            0 : OksSystem::Executable::pipe_in(const param_collection& params) const
     346              : {
     347              : 
     348            0 :   int input_pipe[2];
     349            0 :   int data_pipe[2];
     350            0 :   int error_pipe[2];
     351            0 :   const int input_pipe_status = pipe(input_pipe);
     352            0 :   if (input_pipe_status < 0)
     353            0 :     throw OksSystem::OksSystemCallIssue(ERS_HERE, errno, "pipe", "");
     354            0 :   const int data_pipe_status = pipe(data_pipe);
     355            0 :   if (data_pipe_status < 0)
     356            0 :     throw OksSystem::OksSystemCallIssue(ERS_HERE, errno, "pipe", "");
     357            0 :   const int error_pipe_status = pipe(error_pipe);
     358            0 :   if (error_pipe_status < 0)
     359            0 :     throw OksSystem::OksSystemCallIssue(ERS_HERE, errno, "pipe", "");
     360              : 
     361              :   // Block all signals before fork()
     362            0 :   sigset_t new_set;
     363            0 :   sigset_t old_set;
     364            0 :   sigfillset(&new_set);
     365            0 :   pthread_sigmask(SIG_SETMASK, &new_set, &old_set);
     366              : 
     367            0 :   const pid_t child_id = fork();
     368            0 :   if (0 == child_id) { // we are the child
     369              : 
     370              :     // Put some signals to their default
     371            0 :     signal(SIGTERM, SIG_DFL);
     372            0 :     signal(SIGINT, SIG_DFL);
     373              : 
     374              :     // Restore the original signal mask in child
     375            0 :     pthread_sigmask(SIG_SETMASK, &old_set, NULL);
     376              : 
     377            0 :     dup2(input_pipe[1], fileno(stdin));
     378            0 :     dup2(data_pipe[1], fileno(stdout));
     379            0 :     dup2(error_pipe[1], fileno(stderr));
     380              : 
     381            0 :     try {
     382            0 :       this->exec(params);
     383            0 :     } catch (OksSystem::ExecutionIssue& ex) {
     384            0 :       ers::warning(ex);
     385            0 :       _exit(EXIT_FAILURE);
     386            0 :     } catch (ers::Issue& ex) {
     387            0 :       ers::warning(ex);
     388            0 :       _exit(EXIT_FAILURE);
     389            0 :     }
     390              : 
     391              :   } // we are the child
     392            0 :   if (child_id > 0) { // we are the parent
     393              : 
     394              :     // Restore the original signal mask in parent
     395            0 :     pthread_sigmask(SIG_SETMASK, &old_set, NULL);
     396              : 
     397            0 :     Process child_process(child_id, to_string(params));
     398            0 :     close(input_pipe[1]);
     399            0 :     close(data_pipe[1]);
     400            0 :     close(error_pipe[1]);
     401            0 :     const int child_status = child_process.join();
     402            0 :     const int in_fd = input_pipe[0];
     403            0 :     const int err_fd = error_pipe[0];
     404            0 :     const int out_fd = data_pipe[0];
     405            0 :     std::ostringstream in_stream;
     406            0 :     std::ostringstream out_stream;
     407            0 :     std::ostringstream err_stream;
     408            0 :     copy_fd(in_fd, in_stream);
     409            0 :     copy_fd(out_fd, out_stream);
     410            0 :     copy_fd(err_fd, err_stream);
     411            0 :     close(in_fd);
     412            0 :     close(out_fd);
     413            0 :     close(err_fd);
     414            0 :     if (0 == child_status) {
     415            0 :       return out_stream.str();
     416              :     } // if
     417            0 :     std::string command = to_string(params);
     418            0 :     std::string error_str = err_stream.str();
     419            0 :     throw OksSystem::ExecutionIssue(ERS_HERE, errno, command.c_str(), child_status);
     420            0 :   } // we are the parent
     421              : 
     422              :   // Restore the original signal mask in case of a fork() failure
     423            0 :   pthread_sigmask(SIG_SETMASK, &old_set, NULL);
     424              : 
     425            0 :   return std::string();
     426              : } // pipe_in
     427              : 
     428              : /** This method executes the process and pipes stdout and stderr back and waits for execution termination.
     429              :  * If the return value is zero then the content of stdout is copied into a string and returned.
     430              :  * In case of a non-zero value, an exception is thrown.
     431              :  * This exception contains the return code and the content of stderr.
     432              :  * \return content of stdout
     433              :  * \param params the parameters to the executable
     434              :  * \param envs the environnement variables to set
     435              :  * \throw OksSystem::ExecutionIssue if command execution did not return 0.
     436              :  * \throw OksSystem::ExecFail if the exec okssystem call failed.
     437              :  * \throw OksSystem::PipeIssue if the pipe okssystem call failed.
     438              :  */
     439              : 
     440              : std::string
     441            0 : OksSystem::Executable::pipe_in(const param_collection& params, const env_collection& envs) const
     442              : {
     443            0 :   OksSystem::Environment::set(envs);
     444            0 :   return pipe_in(params);
     445              : } // pipe_in
     446              : 
     447              : /** \overload */
     448              : 
     449              : OksSystem::Process
     450            0 : OksSystem::Executable::pipe_out(const param_collection& params,
     451              :                                 const File& input_file,
     452              :                                 const File& output_file,
     453              :                                 const File& error_file,
     454              :                                 mode_t perm) const
     455              : {
     456              : 
     457              :   // Block all signals before fork()
     458            0 :   sigset_t new_set;
     459            0 :   sigset_t old_set;
     460            0 :   sigfillset(&new_set);
     461            0 :   pthread_sigmask(SIG_SETMASK, &new_set, &old_set);
     462              : 
     463            0 :   OksSystem::Descriptor in(
     464            0 :     &input_file, OksSystem::Descriptor::flags(true, false), perm); // May throw OksSystem::OpenFileIssue
     465            0 :   OksSystem::Descriptor out(&output_file, OksSystem::Descriptor::flags(false, true), perm);
     466            0 :   OksSystem::Descriptor err(&error_file, OksSystem::Descriptor::flags(false, true), perm);
     467              : 
     468            0 :   const pid_t child_id = fork();
     469            0 :   if (0 == child_id) { // we are the child
     470              : 
     471              :     // Put some signals to their default
     472            0 :     signal(SIGTERM, SIG_DFL);
     473            0 :     signal(SIGINT, SIG_DFL);
     474              : 
     475              :     // Restore the original signal mask in child
     476            0 :     pthread_sigmask(SIG_SETMASK, &old_set, NULL);
     477              : 
     478            0 :     try {
     479            0 :       ::dup2(in, ::fileno(stdin));
     480            0 :       ::dup2(out, ::fileno(stdout));
     481            0 :       ::dup2(err, ::fileno(stderr));
     482            0 :       ::close(in.fd());
     483            0 :       ::close(out.fd());
     484            0 :       ::close(err.fd());
     485            0 :       this->exec(params);
     486            0 :     } catch (OksSystem::ExecutionIssue& ex) {
     487            0 :       ers::warning(ex);
     488            0 :       _exit(EXIT_FAILURE);
     489            0 :     } catch (OksSystem::PosixIssue& ex) {
     490            0 :       ers::warning(ex);
     491            0 :       _exit(EXIT_FAILURE);
     492            0 :     } catch (ers::Issue& ex) {
     493            0 :       ers::warning(ex);
     494            0 :       _exit(EXIT_FAILURE);
     495            0 :     }
     496              : 
     497              :   } // we are the child
     498            0 :   if (child_id > 0) { // we are the parent
     499              : 
     500              :     // Restore the original signal mask in parent
     501            0 :     pthread_sigmask(SIG_SETMASK, &old_set, NULL);
     502              : 
     503            0 :     return Process(child_id, to_string(params));
     504              :   } // we are the parent
     505              : 
     506              :   // Restore the original signal mask in case of a fork() failure
     507            0 :   pthread_sigmask(SIG_SETMASK, &old_set, NULL);
     508              : 
     509            0 :   throw OksSystem::OksSystemCallIssue(ERS_HERE, errno, "fork", ""); // We are screwed up
     510            0 : } // pipe_out
     511              : 
     512              : /** Runs the executable and redirects the two output streams
     513              :  * \param params the parameters for the executable
     514              :  * \param envs the environnements for the executable
     515              :  * \param input_file the input file for stdin
     516              :  * \param output_file the output file for stdout
     517              :  * \param error_file the output file for stderr
     518              :  * \param perm permissions for both output streams
     519              :  */
     520              : 
     521              : OksSystem::Process
     522            0 : OksSystem::Executable::pipe_out(const param_collection& params,
     523              :                                 const env_collection& envs,
     524              :                                 const File& input_file,
     525              :                                 const File& output_file,
     526              :                                 const File& error_file,
     527              :                                 mode_t perm) const
     528              : {
     529              : 
     530              :   // Block all signals before fork()
     531            0 :   sigset_t new_set;
     532            0 :   sigset_t old_set;
     533            0 :   sigfillset(&new_set);
     534            0 :   pthread_sigmask(SIG_SETMASK, &new_set, &old_set);
     535              : 
     536            0 :   OksSystem::Descriptor in(
     537            0 :     &input_file, OksSystem::Descriptor::flags(true, false), perm); // May throw OksSystem::OpenFileIssue
     538            0 :   OksSystem::Descriptor out(&output_file, OksSystem::Descriptor::flags(false, true), perm);
     539            0 :   OksSystem::Descriptor err(&error_file, OksSystem::Descriptor::flags(false, true), perm);
     540              : 
     541            0 :   const pid_t child_id = fork();
     542            0 :   if (0 == child_id) { // we are the child
     543              : 
     544              :     // Put some signals to their default
     545            0 :     signal(SIGTERM, SIG_DFL);
     546            0 :     signal(SIGINT, SIG_DFL);
     547              : 
     548              :     // Restore the original signal mask in child
     549            0 :     pthread_sigmask(SIG_SETMASK, &old_set, NULL);
     550              : 
     551            0 :     try {
     552            0 :       ::dup2(in, ::fileno(stdin));
     553            0 :       ::dup2(out, ::fileno(stdout));
     554            0 :       ::dup2(err, ::fileno(stderr));
     555            0 :       ::close(in.fd());
     556            0 :       ::close(out.fd());
     557            0 :       ::close(err.fd());
     558            0 :       this->exec(params, envs);
     559            0 :     } catch (OksSystem::ExecutionIssue& ex) {
     560            0 :       ers::warning(ex);
     561            0 :       _exit(EXIT_FAILURE);
     562            0 :     } catch (OksSystem::PosixIssue& ex) {
     563            0 :       ers::warning(ex);
     564            0 :       _exit(EXIT_FAILURE);
     565            0 :     } catch (ers::Issue& ex) {
     566            0 :       ers::warning(ex);
     567            0 :       _exit(EXIT_FAILURE);
     568            0 :     }
     569              : 
     570              :   } // we are the child
     571            0 :   if (child_id > 0) { // we are the parent
     572              : 
     573              :     // Restore the original signal mask in parent
     574            0 :     pthread_sigmask(SIG_SETMASK, &old_set, NULL);
     575              : 
     576            0 :     return Process(child_id, to_string(params));
     577              :   } // we are the parent
     578              : 
     579              :   // Restore the original signal mask in case of a fork() failure
     580            0 :   pthread_sigmask(SIG_SETMASK, &old_set, NULL);
     581              : 
     582            0 :   throw OksSystem::OksSystemCallIssue(ERS_HERE, errno, "fork", ""); // We are screwed up
     583              : 
     584            0 : } // pipe_out
     585              : 
     586              : /** This method starts the executable in another process using \c fork
     587              :  * \param params the parameters to use when launching the executable
     588              :  * \param envs table of the environnement variables set for the executable
     589              :  */
     590              : 
     591              : OksSystem::Process
     592            0 : OksSystem::Executable::start(const param_collection& params, const env_collection& envs) const
     593              : {
     594              : 
     595              :   // Block all signals before fork()
     596            0 :   sigset_t new_set;
     597            0 :   sigset_t old_set;
     598            0 :   sigfillset(&new_set);
     599            0 :   pthread_sigmask(SIG_SETMASK, &new_set, &old_set);
     600              : 
     601            0 :   const pid_t child_id = fork();
     602            0 :   if (child_id == 0) { // we are the child
     603              : 
     604              :     // Put some signals to their default
     605            0 :     signal(SIGTERM, SIG_DFL);
     606            0 :     signal(SIGINT, SIG_DFL);
     607              : 
     608              :     // Restore the original signal mask in child
     609            0 :     pthread_sigmask(SIG_SETMASK, &old_set, NULL);
     610              : 
     611            0 :     try {
     612            0 :       exec(params, envs);
     613            0 :     } catch (OksSystem::ExecutionIssue& ex) {
     614            0 :       ers::warning(ex);
     615            0 :       _exit(EXIT_FAILURE);
     616            0 :     } catch (ers::Issue& ex) {
     617            0 :       ers::warning(ex);
     618            0 :       _exit(EXIT_FAILURE);
     619            0 :     }
     620              : 
     621              :   } // we are the child
     622            0 :   if (child_id > 0) { // we are the parent
     623              : 
     624              :     // Restore the original signal mask in parent
     625            0 :     pthread_sigmask(SIG_SETMASK, &old_set, NULL);
     626              : 
     627            0 :     return Process(child_id);
     628              :   } // we are the parent
     629              : 
     630              :   // Restore the original signal mask in case of a fork() failure
     631            0 :   pthread_sigmask(SIG_SETMASK, &old_set, NULL);
     632              : 
     633            0 :   throw OksSystem::OksSystemCallIssue(ERS_HERE, errno, "fork", ""); // We are screwed up
     634              : } // start
     635              : 
     636              : /** Converts the executable name and a list of parameters into a string,
     637              :  * suitable for display.
     638              :  * \param params the list of parameters
     639              :  * \return a string with command name and parameters separated by spaces
     640              :  */
     641              : 
     642              : std::string
     643            0 : OksSystem::Executable::to_string(const param_collection& params) const
     644              : {
     645            0 :   std::ostringstream stream;
     646            0 :   stream << m_full_name;
     647            0 :   for (param_collection::const_iterator pos = params.begin(); pos != params.end(); ++pos) {
     648            0 :     stream << " " << (*pos);
     649              :   } // for
     650            0 :   return stream.str();
     651            0 : } // to_string
        

Generated by: LCOV version 2.0-1