"Fossies" - the Fresh Open Source Software Archive

Member "src/Platform/Unix/Process.cpp" (10 Oct 2018, 6182 Bytes) of package /windows/misc/VeraCrypt_1.23-Hotfix-2_Source.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "Process.cpp" see the Fossies "Dox" file reference documentation.

    1 /*
    2  Derived from source code of TrueCrypt 7.1a, which is
    3  Copyright (c) 2008-2012 TrueCrypt Developers Association and which is governed
    4  by the TrueCrypt License 3.0.
    5 
    6  Modifications and additions to the original source code (contained in this file)
    7  and all other portions of this file are Copyright (c) 2013-2017 IDRIX
    8  and are governed by the Apache License 2.0 the full text of which is
    9  contained in the file License.txt included in VeraCrypt binary and source
   10  code distribution packages.
   11 */
   12 
   13 #include <errno.h>
   14 #include <fcntl.h>
   15 #include <unistd.h>
   16 #include <sys/stat.h>
   17 #include <sys/wait.h>
   18 #include "Process.h"
   19 #include "Platform/Exception.h"
   20 #include "Platform/FileStream.h"
   21 #include "Platform/ForEach.h"
   22 #include "Platform/MemoryStream.h"
   23 #include "Platform/SystemException.h"
   24 #include "Platform/StringConverter.h"
   25 #include "Platform/Unix/Pipe.h"
   26 #include "Platform/Unix/Poller.h"
   27 
   28 namespace VeraCrypt
   29 {
   30     string Process::Execute (const string &processName, const list <string> &arguments, int timeOut, ProcessExecFunctor *execFunctor, const Buffer *inputData)
   31     {
   32         char *args[32];
   33         if (array_capacity (args) <= arguments.size())
   34             throw ParameterTooLarge (SRC_POS);
   35 
   36 #if 0
   37         stringstream dbg;
   38         dbg << "exec " << processName;
   39         foreach (const string &at, arguments)
   40             dbg << " " << at;
   41         trace_msg (dbg.str());
   42 #endif
   43 
   44         Pipe inPipe, outPipe, errPipe, exceptionPipe;
   45 
   46         int forkedPid = fork();
   47         throw_sys_if (forkedPid == -1);
   48 
   49         if (forkedPid == 0)
   50         {
   51             try
   52             {
   53                 try
   54                 {
   55                     int argIndex = 0;
   56                     /* Workaround for gcc 5.X issue related to the use of STL (string and list) with muliple fork calls.
   57                      *
   58                      * The char* pointers retrieved from the elements of parameter "arguments" are no longer valid after
   59                      * a second fork is called. "arguments" was created in the parent of the current child process.
   60                      *
   61                      * The only solution is to copy the elements of "arguments" parameter in a local string array on this
   62                      * child process and then use char* pointers retrieved from this local copies before calling fork.
   63                      *
   64                      * gcc 4.x doesn't suffer from this issue.
   65                      *
   66                      */
   67                     string argsCopy[array_capacity (args)];
   68                     if (!execFunctor)
   69                     {
   70                         argsCopy[argIndex++] = processName;
   71                     }
   72 
   73                     foreach (const string &arg, arguments)
   74                     {
   75                         argsCopy[argIndex++] = arg;
   76                     }
   77 
   78                     for (int i = 0; i < argIndex; i++)
   79                     {
   80                         args[i] = const_cast <char*> (argsCopy[i].c_str());
   81                     }
   82 
   83                     args[argIndex] = nullptr;
   84 
   85                     if (inputData)
   86                     {
   87                         throw_sys_if (dup2 (inPipe.GetReadFD(), STDIN_FILENO) == -1);
   88                     }
   89                     else
   90                     {
   91                         inPipe.Close();
   92                         int nullDev = open ("/dev/null", 0);
   93                         throw_sys_sub_if (nullDev == -1, "/dev/null");
   94                         throw_sys_if (dup2 (nullDev, STDIN_FILENO) == -1);
   95                     }
   96 
   97                     throw_sys_if (dup2 (outPipe.GetWriteFD(), STDOUT_FILENO) == -1);
   98                     throw_sys_if (dup2 (errPipe.GetWriteFD(), STDERR_FILENO) == -1);
   99                     exceptionPipe.GetWriteFD();
  100 
  101                     if (execFunctor)
  102                     {
  103                         (*execFunctor)(argIndex, args);
  104                     }
  105                     else
  106                     {
  107                         execvp (args[0], args);
  108                         throw SystemException (SRC_POS, args[0]);
  109                     }
  110                 }
  111                 catch (Exception &)
  112                 {
  113                     throw;
  114                 }
  115                 catch (exception &e)
  116                 {
  117                     throw ExternalException (SRC_POS, StringConverter::ToExceptionString (e));
  118                 }
  119                 catch (...)
  120                 {
  121                     throw UnknownException (SRC_POS);
  122                 }
  123             }
  124             catch (Exception &e)
  125             {
  126                 try
  127                 {
  128                     shared_ptr <Stream> outputStream (new FileStream (exceptionPipe.GetWriteFD()));
  129                     e.Serialize (outputStream);
  130                 }
  131                 catch (...) { }
  132             }
  133 
  134             _exit (1);
  135         }
  136 
  137         throw_sys_if (fcntl (outPipe.GetReadFD(), F_SETFL, O_NONBLOCK) == -1);
  138         throw_sys_if (fcntl (errPipe.GetReadFD(), F_SETFL, O_NONBLOCK) == -1);
  139         throw_sys_if (fcntl (exceptionPipe.GetReadFD(), F_SETFL, O_NONBLOCK) == -1);
  140 
  141         vector <char> buffer (4096), stdOutput (4096), errOutput (4096), exOutput (4096);
  142         buffer.clear ();
  143         stdOutput.clear ();
  144         errOutput.clear ();
  145         exOutput.clear ();
  146 
  147         Poller poller (outPipe.GetReadFD(), errPipe.GetReadFD(), exceptionPipe.GetReadFD());
  148         int status, waitRes;
  149 
  150         if (inputData)
  151             throw_sys_if (write (inPipe.GetWriteFD(), inputData->Ptr(), inputData->Size()) == -1 && errno != EPIPE);
  152 
  153         inPipe.Close();
  154 
  155         int timeTaken = 0;
  156         do
  157         {
  158             const int pollTimeout = 200;
  159             try
  160             {
  161                 ssize_t bytesRead = 0;
  162                 foreach (int fd, poller.WaitForData (pollTimeout))
  163                 {
  164                     bytesRead = read (fd, &buffer[0], buffer.capacity());
  165                     if (bytesRead > 0)
  166                     {
  167                         if (fd == outPipe.GetReadFD())
  168                             stdOutput.insert (stdOutput.end(), buffer.begin(), buffer.begin() + bytesRead);
  169                         else if (fd == errPipe.GetReadFD())
  170                             errOutput.insert (errOutput.end(), buffer.begin(), buffer.begin() + bytesRead);
  171                         else if (fd == exceptionPipe.GetReadFD())
  172                             exOutput.insert (exOutput.end(), buffer.begin(), buffer.begin() + bytesRead);
  173                     }
  174                 }
  175 
  176                 if (bytesRead == 0)
  177                 {
  178                     waitRes = waitpid (forkedPid, &status, 0);
  179                     break;
  180                 }
  181             }
  182             catch (TimeOut&)
  183             {
  184                 timeTaken += pollTimeout;
  185                 if (timeOut >= 0 && timeTaken >= timeOut)
  186                     throw;
  187             }
  188         } while ((waitRes = waitpid (forkedPid, &status, WNOHANG)) == 0);
  189         throw_sys_if (waitRes == -1);
  190 
  191         if (!exOutput.empty())
  192         {
  193             auto_ptr <Serializable> deserializedObject;
  194             Exception *deserializedException = nullptr;
  195 
  196             try
  197             {
  198                 shared_ptr <Stream> stream (new MemoryStream (ConstBufferPtr ((byte *) &exOutput[0], exOutput.size())));
  199                 deserializedObject.reset (Serializable::DeserializeNew (stream));
  200                 deserializedException = dynamic_cast <Exception*> (deserializedObject.get());
  201             }
  202             catch (...) { }
  203 
  204             if (deserializedException)
  205                 deserializedException->Throw();
  206         }
  207 
  208         int exitCode = (WIFEXITED (status) ? WEXITSTATUS (status) : 1);
  209         if (exitCode != 0)
  210         {
  211             string strErrOutput;
  212 
  213             if (!errOutput.empty())
  214                 strErrOutput.insert (strErrOutput.begin(), errOutput.begin(), errOutput.end());
  215 
  216             throw ExecutedProcessFailed (SRC_POS, processName, exitCode, strErrOutput);
  217         }
  218 
  219         string strOutput;
  220 
  221         if (!stdOutput.empty())
  222             strOutput.insert (strOutput.begin(), stdOutput.begin(), stdOutput.end());
  223 
  224         return strOutput;
  225     }
  226 }