LCOV - code coverage report
Current view: top level - snapwebsites - process.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1 431 0.2 %
Date: 2019-12-15 17:13:15 Functions: 2 70 2.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // Snap Websites Server -- C++ object to run advance processes
       2             : // Copyright (c) 2013-2019  Made to Order Software Corp.  All Rights Reserved
       3             : //
       4             : // This program is free software; you can redistribute it and/or modify
       5             : // it under the terms of the GNU General Public License as published by
       6             : // the Free Software Foundation; either version 2 of the License, or
       7             : // (at your option) any later version.
       8             : //
       9             : // This program is distributed in the hope that it will be useful,
      10             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             : // GNU General Public License for more details.
      13             : //
      14             : // You should have received a copy of the GNU General Public License
      15             : // along with this program; if not, write to the Free Software
      16             : // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
      17             : 
      18             : 
      19             : // self
      20             : //
      21             : #include "snapwebsites/process.h"
      22             : 
      23             : 
      24             : // snapwebsites lib
      25             : //
      26             : #include "snapwebsites/log.h"
      27             : 
      28             : 
      29             : // C++ lib
      30             : //
      31             : #include <fstream>
      32             : 
      33             : 
      34             : // C lib
      35             : //
      36             : #include <proc/readproc.h>
      37             : #include <stdio.h>
      38             : #include <sys/prctl.h>
      39             : #include <sys/wait.h>
      40             : #include <unistd.h>
      41             : 
      42             : 
      43             : // last include
      44             : //
      45             : #include <snapdev/poison.h>
      46             : 
      47             : 
      48             : 
      49             : 
      50             : 
      51             : extern char ** environ;
      52             : 
      53             : namespace snap
      54             : {
      55             : 
      56             : 
      57             : /** \class process::process_output_callback
      58             :  * \brief Callback to inform the caller of new output.
      59             :  *
      60             :  * In case the input depends no the output of a command line process, we
      61             :  * create a callback. This class is used for that purpose.
      62             :  *
      63             :  * The callback is called any time some output is received and the read()
      64             :  * returns. The callback itself is called with exactly what is received.
      65             :  * However, the output data read from the read() function is added to the
      66             :  * f_output variable member of the process generating a larger output buffer,
      67             :  * eventually encompassing the whole output of the process.
      68             :  *
      69             :  * The process class shows a graph of the different processes including the
      70             :  * callback.
      71             :  *
      72             :  * \todo
      73             :  * We may want to reconsider keeping all the output of the read() function
      74             :  * in case we have a callback since that requires a lot of memory in one
      75             :  * single block.
      76             :  */
      77             : 
      78             : 
      79             : /** \fn process::process_output_callback::output_available();
      80             :  * \brief The function called any time output is available.
      81             :  *
      82             :  * This callback function is called whenever the read() of the output
      83             :  * thread returns some data. In case of the interactive version, that may
      84             :  * me quite often as the pipe is made non-blocking.
      85             :  *
      86             :  * The callback is generally expected to make use of the output and then
      87             :  * eventually send more input by calling the process set_input() function.
      88             :  *
      89             :  * In most cases, no output callback is defined unless interaction with
      90             :  * the output of the child process is required. In that case things go
      91             :  * faster as the data gets cached in many ways.
      92             :  *
      93             :  * Note that whether your callback function received enough data or not,
      94             :  * it must return normally for the thread to continue processing the
      95             :  * output of the child process.
      96             :  *
      97             :  * \todo
      98             :  * At this point the output thread is not protected against exceptions.
      99             :  * However, it is likely to block the entire process if an exception occurs!
     100             :  *
     101             :  * \param[in] p  A pointer to the process.
     102             :  * \param[in] output  The output just received by the last read() call.
     103             :  */
     104             : 
     105             : 
     106             : 
     107             : 
     108             : 
     109             : /** \class process
     110             :  * \brief A process class to run a process and get information about the results.
     111             :  *
     112             :  * This class is used to run processes. Especially, it can run with in and
     113             :  * out capabilities (i.e. piping) although this is generally not recommanded
     114             :  * because piping can block (if you do not send enough data, or do not read
     115             :  * enough data, then the pipes can get stuck.) We use a thread to read the
     116             :  * results. We do not currently expect that the use of this class will require
     117             :  * the input read to be necessary to know what needs to be written (i.e. in
     118             :  * most cases all we want is to convert a file [input] from one format to
     119             :  * another [output] avoiding reading/writing on disk.)
     120             :  *
     121             :  * The whole process, when using the interactive mode, is quite complicated
     122             :  * so I wrote the following diagram. As you can see, the loop of sending
     123             :  * and receiving data from the child process is fairly simple. Note that the
     124             :  * callback is called from the Output Thread, not the main process. This does
     125             :  * not make much of a difference because no other function can be running on
     126             :  * the main process when that happens. The output is blocked and thus the
     127             :  * output variable is safe. The input is not blocked but adding input was
     128             :  * made safe internally.
     129             :  *
     130             :  * \msc
     131             :  * hscale = "2";
     132             :  * a [label="Function"],b [label="Process"],c [label="Input Thread"],d [label="Output Thread"],e [label="Child Process"];
     133             :  *
     134             :  * a=>b [label="run()"];
     135             :  * b=>e [label="fork()"];
     136             :  * e->e [label="execvpe()"];
     137             :  * b=>c [label="pthread_create()"];
     138             :  * b=>d [label="pthread_create()"];
     139             :  * b=>e [label="wait() child's death"];
     140             :  *
     141             :  * --- [label="start repeat"];
     142             :  * c->e [label="write() (Input Data)"];
     143             :  * d<-e [label="read() (Output Data)"];
     144             :  * b<:d [label="output shared"];
     145             :  * a<<=d [label="output callback"];
     146             :  * a=>b [label="set_input()"];
     147             :  * b=>c [label="add input"];
     148             :  * --- [label="end repeat"];
     149             :  *
     150             :  * b<-e [label="child died"];
     151             :  * b->c [label="stop()"];
     152             :  * b<-c [label="stopped"];
     153             :  * b->d [label="stop()"];
     154             :  * b<-d [label="stopped"];
     155             :  * a<<b [label="run()"];
     156             :  * \endmsc
     157             :  */
     158             : 
     159             : 
     160             : /** \brief Do nothing implementation of error_avalable()
     161             :  *
     162             :  * By default a process error stream is not used.
     163             :  *
     164             :  * \warning
     165             :  * The error buffer will represent UTF-8 data on Linux, however, when
     166             :  * this callback gets called, the buffer may not yet be complete and
     167             :  * thus attempting to convert to UTF-8 may fail in various ways.
     168             :  *
     169             :  * \todo
     170             :  * What we want to do is send the error output to SNAP_LOG_ERROR().
     171             :  * For that, however, we need to parse strings out of the \p error
     172             :  * parameter which we do not do yet.
     173             :  *
     174             :  * \param[in,out] p  The process that generated this error output.
     175             :  * \param[in] error  The error data, probably UTF-8, but it can be incomplete.
     176             :  */
     177           0 : bool process::process_output_callback::error_available(process * p, QByteArray const & error)
     178             : {
     179           0 :     NOTUSED(p);
     180           0 :     NOTUSED(error);
     181             : 
     182           0 :     return true;
     183             : }
     184             : 
     185             : 
     186             : /** \brief Initialize the process object.
     187             :  *
     188             :  * This function saves the name of the process. The name is generally a
     189             :  * static string and it is used to distinguish between processes when
     190             :  * managing several at once. The function makes a copy of the name.
     191             :  *
     192             :  * \param[in] name  The name of the process.
     193             :  */
     194           0 : process::process(QString const & name)
     195           0 :     : f_name(name)
     196             : {
     197           0 : }
     198             : 
     199             : 
     200             : /** \brief Retrieve the name of this process object.
     201             :  *
     202             :  * This process object is given a name on creation. In most cases this is
     203             :  * a static name that is used to determine which process is which.
     204             :  *
     205             :  * \return The name of the process.
     206             :  */
     207           0 : QString const & process::get_name() const
     208             : {
     209           0 :     return f_name;
     210             : }
     211             : 
     212             : 
     213             : /** \brief Set the management mode.
     214             :  *
     215             :  * This function defines the mode that the process is going to use when
     216             :  * running. It cannot be changed once the process is started (the run()
     217             :  * function was called.)
     218             :  *
     219             :  * The available modes are:
     220             :  *
     221             :  * \li PROCESS_MODE_COMMAND
     222             :  *
     223             :  * Run a simple command (i.e. very much like system() would.)
     224             :  *
     225             :  * \li PROCESS_MODE_INPUT
     226             :  *
     227             :  * Run a process that wants some input. We write data to its input. It
     228             :  * does not generate output (i.e. sendmail).
     229             :  *
     230             :  * \li PROCESS_MODE_OUTPUT
     231             :  *
     232             :  * Run a process that generates output. We read the output.
     233             :  *
     234             :  * \li PROCESS_MODE_INOUT
     235             :  *
     236             :  * Run the process in a way so we can write input to it, and read its
     237             :  * output from it. This is one of the most useful mode. This mode does
     238             :  * not give you any interaction capabilities (i.e. what comes in the
     239             :  * output cannot be used to intervene with what is sent to the input.)
     240             :  *
     241             :  * This is extermely useful to run filter commands (i.e. html2text).
     242             :  *
     243             :  * \li PROCESS_MODE_INOUTERR
     244             :  *
     245             :  * Run the process in a way so we can write input to it, and read
     246             :  * both output: stdout and stderr. This is similar to the
     247             :  * PROCESS_MODE_INOUT except that you can distinguish the error
     248             :  * feed from the non-error feed.
     249             :  *
     250             :  * \li PROCESS_MODE_INOUT_INTERACTIVE
     251             :  *
     252             :  * Run the process interactively, meaning that its output is going to be
     253             :  * read and interpreted to determine what the input is going to be. This
     254             :  * is a very complicated mode and it should be avoided if possible because
     255             :  * it is not unlikely that the process will end up blocking. To be on the
     256             :  * safe side, look into whether it would be possible to transform that
     257             :  * process in a server and connect to it instead.
     258             :  *
     259             :  * Otherwise this mode is similar to the in/out mode only the output is
     260             :  * used to know to further feed in the input.
     261             :  *
     262             :  * \param[in] mode  The mode of the process.
     263             :  */
     264           0 : void process::set_mode(mode_t mode)
     265             : {
     266           0 :     f_mode = mode;
     267           0 : }
     268             : 
     269             : 
     270             : /** \brief Set how the environment variables are defined in the process.
     271             :  *
     272             :  * By default all the environment variables from the current process are
     273             :  * passed to the child process. If the child process is not 100% trustworthy,
     274             :  * however, it may be preferable to only pass a specific set of environment
     275             :  * variable (as added by the add_environment() function) to the child process.
     276             :  * This function, when called with true (the default) does just that.
     277             :  *
     278             :  * \param[in] forced  Whether the environment will be forced.
     279             :  */
     280           0 : void process::set_forced_environment(bool forced)
     281             : {
     282           0 :     f_forced_environment = forced;
     283           0 : }
     284             : 
     285             : 
     286             : /** \brief Define the command to run.
     287             :  *
     288             :  * The command name may be a full path or just the command filename.
     289             :  * (i.e. the execvp() function makes use of the PATH variable to find
     290             :  * the command on disk unless the \p command parameter includes a
     291             :  * slash character.)
     292             :  *
     293             :  * If the process cannot be found an error is generated at the time you
     294             :  * call the run() function.
     295             :  *
     296             :  * \param[in] command  The command to start the new process.
     297             :  */
     298           0 : void process::set_command(QString const & command)
     299             : {
     300           0 :     f_command = command;
     301           0 : }
     302             : 
     303             : 
     304             : /** \brief Define the command to run.
     305             :  *
     306             :  * This is an overload to set the command to run.
     307             :  *
     308             :  * \param[in] command  The command to start the new process.
     309             :  */
     310           0 : void process::set_command(std::string const & command)
     311             : {
     312           0 :     f_command = QString::fromUtf8(command.c_str());
     313           0 : }
     314             : 
     315             : 
     316             : /** \brief Define the command to run.
     317             :  *
     318             :  * This is an overload to set the command to run.
     319             :  *
     320             :  * \param[in] command  The command to start the new process.
     321             :  */
     322           0 : void process::set_command(char const * command)
     323             : {
     324           0 :     f_command = QString::fromUtf8(command);
     325           0 : }
     326             : 
     327             : 
     328             : /** \brief Add an argument to the command line.
     329             :  *
     330             :  * This function adds one individual arguement to the command line.
     331             :  * You have to add all the arguments in the right order.
     332             :  *
     333             :  * \param[in] arg  The argument to be added.
     334             :  */
     335           0 : void process::add_argument(QString const & arg)
     336             : {
     337           0 :     f_arguments.push_back(arg);
     338           0 : }
     339             : 
     340             : 
     341             : /** \brief Add an argument to the command line.
     342             :  *
     343             :  * This is an overload to accept std::string's of UTF-8 characters.
     344             :  *
     345             :  * \param[in] arg  The argument to be added.
     346             :  */
     347           0 : void process::add_argument(std::string const & arg)
     348             : {
     349           0 :     add_argument(QString::fromUtf8(arg.c_str()));
     350           0 : }
     351             : 
     352             : 
     353             : /** \brief Add an argument to the command line.
     354             :  *
     355             :  * This is an overload to accept plain strings of UTF-8 characters.
     356             :  *
     357             :  * \param[in] arg  The argument to be added.
     358             :  */
     359           0 : void process::add_argument(char const * arg)
     360             : {
     361           0 :     add_argument(QString::fromUtf8(arg));
     362           0 : }
     363             : 
     364             : 
     365             : /** \brief Add an environment to the command line.
     366             :  *
     367             :  * This function adds a new environment variable for the child process to
     368             :  * use. In most cases this function doesn't get used.
     369             :  *
     370             :  * By default all the parent process (this current process) environment
     371             :  * variables are passed down to the child process. To avoid this behavior,
     372             :  * call the set_forced_environment() function before the run() function.
     373             :  *
     374             :  * An environment variable is defined as a name, and a value as in:
     375             :  *
     376             :  * \code
     377             :  * add_environ("HOME", "/home/snap");
     378             :  * \endcode
     379             :  *
     380             :  * If the value is set to the empty string, then the environment variable
     381             :  * is removed from the list.
     382             :  *
     383             :  * \param[in] name  The name of the environment variable to add.
     384             :  * \param[in] value  The new value of that environment variable.
     385             :  */
     386           0 : void process::add_environ(QString const & name, QString const & value)
     387             : {
     388           0 :     if(value.isEmpty())
     389             :     {
     390           0 :         environment_map_t::const_iterator it(f_environment.find(name.toUtf8().data()));
     391           0 :         if(it != f_environment.end())
     392             :         {
     393           0 :             f_environment.erase(it);
     394             :         }
     395             :     }
     396             :     else
     397             :     {
     398           0 :         f_environment[name.toUtf8().data()] = value.toUtf8().data();
     399             :     }
     400           0 : }
     401             : 
     402             : 
     403             : /** \brief Run the process and return once done.
     404             :  *
     405             :  * This function creates all the necessary things that the process requires
     406             :  * and run the command and then return the exit code as the result.
     407             :  *
     408             :  * If the function encounters problems before it can run the child process,
     409             :  * it returns -1 instead.
     410             :  *
     411             :  * The process tries to use system() or popen() if possible making it less
     412             :  * likely to fail as those are programmed in the C library. If more is asked
     413             :  * of the process (i.e. input and output are required) then the more
     414             :  * complicated process is used, creating two pipes, creating a child process
     415             :  * with fork() and two threads to handle the read and writing of the input and
     416             :  * output pipes.
     417             :  *
     418             :  * \todo
     419             :  * The interactive version of the process is not yet implemented. We do not
     420             :  * need it yet so we did not work on it.
     421             :  *
     422             :  * \todo
     423             :  * The threads only handle standard exceptions. Non-standard exceptions
     424             :  * will likely terminate the whole process.
     425             :  *
     426             :  * \todo
     427             :  * Change the current pipe() call with the "two way pipes" socketpair()
     428             :  * if that indeed runs faster. Both sockets can be used to read and
     429             :  * write data, instead of 4 descriptors in case of the pipe() call.
     430             :  *
     431             :  * \todo
     432             :  * The raii_pipe class blocks the SIGPIPE and then restores it to whatever
     433             :  * it was before. This may clash with other such calls in other places.
     434             :  * We should instead have one place where we block such calls, always.
     435             :  *
     436             :  * \return The exit code of the child process (0 to 255)
     437             :  *         or -1 if an error occurs
     438             :  */
     439           0 : int process::run()
     440             : {
     441             :     class raii_pipe
     442             :     {
     443             :     public:
     444           0 :         raii_pipe(QString const & command, snap_string_list const & arguments)
     445           0 :         {
     446           0 :             QString cmd(command);
     447           0 :             if(!arguments.isEmpty())
     448             :             {
     449           0 :                 cmd += " " + arguments.join(" ");
     450             :             }
     451           0 :             f_command = cmd;
     452             : 
     453             :             // block the SIGPIPE signal so the process does not end up with
     454             :             // a SIGPIPE error; instead you should be able to detect the
     455             :             // return type as erroneous (i.e. not 0.)
     456             :             //
     457             :             sigset_t set;
     458           0 :             sigemptyset(&set);
     459           0 :             sigaddset(&set, SIGPIPE);
     460           0 :             sigprocmask(SIG_BLOCK, &set, &f_signal_mask);
     461           0 :         }
     462             : 
     463             :         raii_pipe(raii_pipe const & rhs) = delete;
     464             :         raii_pipe & operator = (raii_pipe const & rhs) = delete;
     465             : 
     466           0 :         ~raii_pipe()
     467           0 :         {
     468             :             // make sure the f_file gets closed
     469           0 :             close_pipe();
     470             : 
     471             :             // restore the status of the process signal mask as it was
     472             :             // before entering the run() function
     473             :             //
     474           0 :             sigprocmask(SIG_BLOCK, &f_signal_mask, nullptr);
     475           0 :         }
     476             : 
     477           0 :         QString const & command_line() const
     478             :         {
     479           0 :             return f_command;
     480             :         }
     481             : 
     482           0 :         FILE * open_pipe(char const * mode)
     483             :         {
     484           0 :             f_file = popen(f_command.toUtf8().data(), mode);
     485           0 :             return f_file;
     486             :         }
     487             : 
     488           0 :         int close_pipe()
     489             :         {
     490           0 :             int r(-1);
     491           0 :             if(f_file != nullptr)
     492             :             {
     493           0 :                 if(ferror(f_file))
     494             :                 {
     495             :                     // must return -1 on error, ignore pclose() return value
     496           0 :                     int const e(pclose(f_file));
     497           0 :                     if(e != 0)
     498             :                     {
     499           0 :                         SNAP_LOG_ERROR("pclose() returned ")(e)(", but it will be ignored because the pipe was marked as erroneous.");
     500             :                     }
     501           0 :                     f_file = nullptr;
     502             :                 }
     503             :                 else
     504             :                 {
     505           0 :                     r = pclose(f_file);
     506           0 :                     f_file = nullptr;
     507             :                 }
     508             :             }
     509           0 :             return r;
     510             :         }
     511             : 
     512             :     private:
     513             :         FILE *                      f_file = nullptr;
     514             :         QString                     f_command = QString();
     515             :         sigset_t                    f_signal_mask = sigset_t();
     516             :     };
     517             : 
     518           0 :     raii_pipe rp(/*this,*/ f_command, f_arguments);
     519           0 :     SNAP_LOG_INFO("Running process \"")(rp.command_line())("\" in mode ")(static_cast<int>(static_cast<mode_t>(f_mode)));
     520             : 
     521             :     // if the user imposes environment restrictions we cannot use system()
     522             :     // or popen(). In that case just use the more complex case anyway.
     523           0 :     if(!f_forced_environment && f_environment.empty())
     524             :     {
     525           0 :         switch(f_mode)
     526             :         {
     527           0 :         case mode_t::PROCESS_MODE_COMMAND:
     528           0 :             return system(rp.command_line().toUtf8().data());
     529             : 
     530           0 :         case mode_t::PROCESS_MODE_INPUT:
     531             :             {
     532           0 :                 FILE * f(rp.open_pipe("w"));
     533           0 :                 if(f == nullptr)
     534             :                 {
     535           0 :                     return -1;
     536             :                 }
     537           0 :                 QByteArray data(f_input);
     538           0 :                 if(fwrite(data.data(), data.size(), 1, f) != 1)
     539             :                 {
     540           0 :                     return -1;
     541             :                 }
     542           0 :                 return rp.close_pipe();
     543             :             }
     544             : 
     545           0 :         case mode_t::PROCESS_MODE_OUTPUT:
     546             :             {
     547           0 :                 FILE * f(rp.open_pipe("r"));
     548           0 :                 if(f == nullptr)
     549             :                 {
     550           0 :                     return -1;
     551             :                 }
     552           0 :                 while(!feof(f) && !ferror(f))
     553             :                 {
     554             :                     char buf[4096];
     555           0 :                     size_t l(fread(buf, 1, sizeof(buf), f));
     556           0 :                     if(l > 0)
     557             :                     {
     558           0 :                         f_output.append(buf, static_cast<int>(l));
     559             :                     }
     560             :                 }
     561           0 :                 return rp.close_pipe();
     562             :             }
     563             : 
     564           0 :         default:
     565             :             // In/Out modes require the more complex case
     566           0 :             break;
     567             : 
     568             :         }
     569             :     }
     570             : 
     571           0 :     if(mode_t::PROCESS_MODE_INOUT_INTERACTIVE == f_mode
     572           0 :     && f_output_callback == nullptr)
     573             :     {
     574             :         // mode is not compatible with the current setup
     575           0 :         throw snap_process_exception_invalid_mode_error("mode cannot be in/out interactive without a callback");
     576             :     }
     577             : 
     578             :     // in this case we want to create a pipe(), fork(), execvp() the
     579             :     // command and have a thread to handle the output separately
     580             :     // from the input
     581             :     class raii_inout_pipes
     582             :     {
     583             :     public:
     584           0 :         ~raii_inout_pipes()
     585           0 :         {
     586           0 :             close();
     587           0 :         }
     588             : 
     589           0 :         void close()
     590             :         {
     591           0 :             for(int i(0); i < 6; ++i)
     592             :             {
     593           0 :                 if(f_pipes[i] != -1)
     594             :                 {
     595           0 :                     ::close(f_pipes[i]);
     596           0 :                     f_pipes[i] = -1;
     597             :                 }
     598             :             }
     599           0 :         }
     600             : 
     601           0 :         int open()
     602             :         {
     603           0 :             close();
     604           0 :             if(pipe(f_pipes + 0) != 0) // for stdin
     605             :             {
     606           0 :                 return -1;
     607             :             }
     608           0 :             if(pipe(f_pipes + 2) != 0) // for stdout
     609             :             {
     610           0 :                 return -1;
     611             :             }
     612           0 :             return pipe(f_pipes + 4); // for stderr (conditional)
     613             :         }
     614             : 
     615             :         int f_pipes[6]{-1, -1, -1, -1, -1, -1};
     616             :     };
     617           0 :     raii_inout_pipes inout;
     618           0 :     if(inout.open() == -1)
     619             :     {
     620           0 :         return -1;
     621             :     }
     622             : 
     623             :     class raii_fork
     624             :     {
     625             :     public:
     626           0 :         raii_fork()
     627           0 :             : f_child(fork())
     628             :         {
     629           0 :         }
     630             : 
     631           0 :         ~raii_fork()
     632           0 :         {
     633             :             // in this case f_child should already be zero, if not we are
     634             :             // throwing or exiting with -1 anyway
     635           0 :             wait();
     636           0 :         }
     637             : 
     638           0 :         int wait()
     639             :         {
     640             :             // TODO: use wait4() to get usage and save that usage in the log
     641           0 :             if(f_child > 0)
     642             :             {
     643             :                 // Warning: the W_EXITCODE() macro may not be defined.
     644             :                 //          in our case it sets status to 0x0100
     645             :                 //
     646           0 :                 int status(W_EXITCODE(1, 0));
     647           0 :                 waitpid( f_child, &status, 0 );
     648             : #pragma GCC diagnostic push
     649             : #pragma GCC diagnostic ignored "-Wold-style-cast"
     650           0 :                 if(WIFEXITED(status))
     651             :                 {
     652           0 :                     f_exit = WEXITSTATUS(status);
     653             :                 }
     654             :                 else
     655             :                 {
     656           0 :                     f_exit = -1;
     657             :                 }
     658             : #pragma GCC diagnostic pop
     659             :             }
     660           0 :             f_child = -1;
     661           0 :             return f_exit;
     662             :         }
     663             : 
     664           0 :         int get_pid() const
     665             :         {
     666           0 :             return f_child;
     667             :         }
     668             : 
     669             :         int get_exit() const
     670             :         {
     671             :             return f_exit;
     672             :         }
     673             : 
     674             :     private:
     675             :         pid_t           f_child = -1;
     676             :         int             f_exit = -1;
     677             :     };
     678           0 :     raii_fork child;
     679           0 :     switch(child.get_pid())
     680             :     {
     681           0 :     case -1:
     682             :         // fork failed
     683             :         //
     684           0 :         return -1;
     685             : 
     686           0 :     case 0:
     687             :         // child
     688             :         //
     689             :         try
     690             :         {
     691             :             // set name of child process
     692             :             //
     693           0 :             set_process_name(f_name);
     694             : 
     695             :             // convert arguments so we can use them with execvpe()
     696             :             //
     697           0 :             std::vector<char const *> args_strings;
     698           0 :             std::string const cmd(f_command.toUtf8().data());
     699           0 :             args_strings.push_back(strdup(cmd.c_str()));
     700           0 :             int const args_max(f_arguments.size());
     701           0 :             for(int i(0); i < args_max; ++i)
     702             :             {
     703           0 :                 args_strings.push_back(strdup(f_arguments[i].toUtf8().data()));
     704             :             }
     705           0 :             args_strings.push_back(nullptr); // NULL terminated
     706             : 
     707             :             // convert arguments so we can use them with execvpe()
     708             :             //
     709           0 :             environment_map_t src_envs(f_environment);
     710           0 :             if(!f_forced_environment)
     711             :             {
     712             :                 // since we do not limit the child to only the specified
     713             :                 // environment, add ours but do not overwrite anything
     714             :                 //
     715           0 :                 for(char ** env(environ); *env != nullptr; ++env)
     716             :                 {
     717           0 :                     char const * s(*env);
     718           0 :                     char const * n(s);
     719           0 :                     while(*s != '\0')
     720             :                     {
     721           0 :                         if(*s == '=')
     722             :                         {
     723           0 :                             std::string const name(n, s - n);
     724             : 
     725             :                             // do not overwrite user overridden values
     726             :                             //
     727           0 :                             if(src_envs.find(name) == src_envs.end())
     728             :                             {
     729             :                                 // in Linux all is UTF-8 so we are already good here
     730             :                                 //
     731           0 :                                 src_envs[name] = s + 1;
     732             :                             }
     733           0 :                             break;
     734             :                         }
     735           0 :                         ++s;
     736             :                     }
     737             :                 }
     738             :             }
     739           0 :             std::vector<char const *> envs_strings;
     740           0 :             for(auto const & it : src_envs)
     741             :             {
     742           0 :                 envs_strings.push_back(strdup((it.first + "=" + it.second).c_str()));
     743             :             }
     744           0 :             envs_strings.push_back(nullptr); // NULL terminated
     745             : 
     746             :             // replace the stdin and stdout (and optionally stderr)
     747             :             // with their respective pipes
     748             :             //
     749           0 :             if(dup2(inout.f_pipes[0], STDIN_FILENO) < 0)  // stdin
     750             :             {
     751           0 :                 throw snap_process_exception_initialization_failed("dup2() of the stdin pipe failed");
     752             :             }
     753           0 :             if(dup2(inout.f_pipes[3], STDOUT_FILENO) < 0)  // stdout
     754             :             {
     755           0 :                 throw snap_process_exception_initialization_failed("dup2() of the stdout pipe failed");
     756             :             }
     757           0 :             if(mode_t::PROCESS_MODE_INOUTERR == f_mode)
     758             :             {
     759           0 :                 if(dup2(inout.f_pipes[5], STDERR_FILENO) < 0)  // stderr
     760             :                 {
     761           0 :                     throw snap_process_exception_initialization_failed("dup2() of the stderr pipe failed");
     762             :                 }
     763             :             }
     764             : 
     765             :             // we duplicated those as required, now close all the
     766             :             // other pipes
     767             :             //
     768           0 :             inout.close();
     769             : 
     770           0 :             execvpe(
     771           0 :                 f_command.toUtf8().data(),
     772           0 :                 const_cast<char * const *>(&args_strings[0]),
     773           0 :                 const_cast<char * const *>(&envs_strings[0])
     774             :             );
     775             : 
     776             :             // the child returns only if execvp() fails, which is possible
     777             :             //
     778           0 :             int const e(errno);
     779           0 :             SNAP_LOG_FATAL("Starting child process \"")(f_command)
     780           0 :                           (" ")(f_arguments.join(" "))
     781           0 :                           ("\" failed. (errno: ")(e)
     782           0 :                           (" -- ")(strerror(e))
     783           0 :                           (")");
     784             :         }
     785           0 :         catch( snap_exception const & except )
     786             :         {
     787           0 :             SNAP_LOG_FATAL("process::run(): snap_exception caught: ")(except.what());
     788             :         }
     789           0 :         catch( std::exception const & std_except )
     790             :         {
     791             :             // the snap_logic_exception is not a snap_exception
     792             :             // and other libraries may generate other exceptions
     793             :             // (i.e. libtld, libQtCassandra...)
     794           0 :             SNAP_LOG_FATAL("process::run(): std::exception caught: ")(std_except.what());
     795             :         }
     796           0 :         catch( ... )
     797             :         {
     798           0 :             SNAP_LOG_FATAL("process::run(): unknown exception caught!");
     799             :         }
     800             :         // the child can't safely return from here
     801           0 :         exit(1);
     802             :         NOTREACHED();
     803             :         return -1;
     804             : 
     805           0 :     default:
     806             :         // parent
     807             :         {
     808             :             // close the sides we do not use here
     809             :             //
     810           0 :             close(inout.f_pipes[0]);
     811           0 :             inout.f_pipes[0] = -1;
     812           0 :             close(inout.f_pipes[3]);
     813           0 :             inout.f_pipes[3] = -1;
     814           0 :             if(mode_t::PROCESS_MODE_INOUTERR != f_mode)
     815             :             {
     816             :                 // we won't be using the stderr pipe at all
     817             :                 //
     818           0 :                 close(inout.f_pipes[4]);
     819             :             }
     820           0 :             close(inout.f_pipes[5]);
     821             : 
     822           0 :             class in_t
     823             :                 : public snap_thread::snap_runner
     824             :             {
     825             :             public:
     826           0 :                 in_t(QByteArray const & input, int & pipe)
     827           0 :                     : snap_runner("process::in")
     828             :                     , f_input(input)
     829           0 :                     , f_pipe(pipe)
     830             :                 {
     831           0 :                 }
     832             : 
     833           0 :                 virtual void run()
     834             :                 {
     835             :                     // TODO: this is not handling the interactive case
     836             :                     //       in the interactive case, additional input
     837             :                     //       may be added as we receive new output
     838             :                     //
     839             :                     //       more or less, this means making the data buffer
     840             :                     //       a copy of any extra input before returning
     841           0 :                     QByteArray data(f_input);
     842           0 :                     if(write(f_pipe, data.data(), data.size()) != data.size())
     843             :                     {
     844             :                         // what do we do here? (i.e. we're in a thread)
     845             :                     }
     846             : 
     847             :                     // TODO:
     848             :                     // the only way to wake up the other side is to close
     849             :                     // once we are done writing data--this won't help in
     850             :                     // case we want some interactive support... (i.e. write
     851             :                     // in the pipe depending on what the output is)
     852           0 :                     close(f_pipe);
     853           0 :                     f_pipe = -1;
     854           0 :                 }
     855             : 
     856             :                 QByteArray const &  f_input;
     857             :                 int &               f_pipe;
     858           0 :             } in(f_input, inout.f_pipes[1]);
     859           0 :             snap_thread in_thread("process::in::thread", &in);
     860           0 :             if(!in_thread.start())
     861             :             {
     862           0 :                 return -1;
     863             :             }
     864             : 
     865             : #pragma GCC diagnostic push
     866             : #pragma GCC diagnostic ignored "-Weffc++"
     867           0 :             class out_t
     868             :                 : public snap_thread::snap_runner
     869             :             {
     870             :             public:
     871           0 :                 out_t(QByteArray & output)
     872           0 :                     : snap_runner("process::out")
     873           0 :                     , f_output(output)
     874             :                     //, f_pipe() -- auto-init
     875             :                     //, f_callback() -- auto-init
     876             :                     //, f_process() -- auto-init
     877             :                 {
     878           0 :                 }
     879             : 
     880           0 :                 virtual void run()
     881             :                 {
     882             :                     // TODO: we need to support the interactive capability
     883             :                     //       at some point, which means making the pipe a
     884             :                     //       non-blocking call which we wait on with a
     885             :                     //       select() and send the output to the callback
     886             :                     //       as soon as available instead of loading as
     887             :                     //       much as possible first (i.e. no buffering)
     888             :                     //       later we could have a line based handler which
     889             :                     //       calls the output_available() whenever a new
     890             :                     //       line of data, delimited by new line (\r or \n)
     891             :                     //       characters, is read (semi-buffering)
     892             :                     for(;;)
     893             :                     {
     894             :                         char buf[4096];
     895           0 :                         ssize_t l(read(f_pipe, buf, sizeof(buf)));
     896           0 :                         if(l <= 0)
     897             :                         {
     898             :                             //if(l < 0) ... manage error?
     899           0 :                             break;
     900             :                         }
     901           0 :                         QByteArray output(buf, static_cast<int>(l));
     902           0 :                         f_output.append(output);
     903           0 :                         if(f_callback != nullptr)
     904             :                         {
     905           0 :                             f_callback(f_process, output);
     906             :                         }
     907           0 :                     }
     908           0 :                 }
     909             : 
     910             :                 QByteArray &                    f_output;
     911             :                 int32_t                         f_pipe = -1;
     912             :                 std::function<bool(process * p, QByteArray const & output)> f_callback = std::function<bool(process * p, QByteArray const & output)>();
     913             :                 process *                       f_process = nullptr;
     914           0 :             } out(f_output);
     915             : #pragma GCC diagnostic pop
     916           0 :             out.f_pipe = inout.f_pipes[2];
     917           0 :             if(f_output_callback != nullptr)
     918             :             {
     919           0 :                 out.f_callback = std::bind(&process_output_callback::output_available
     920             :                                          , f_output_callback
     921             :                                          , std::placeholders::_1
     922             :                                          , std::placeholders::_2);
     923             :             }
     924           0 :             out.f_process = this;
     925           0 :             snap_thread out_thread("process::out::thread", &out);
     926           0 :             if(!out_thread.start())
     927             :             {
     928           0 :                 return -1;
     929             :             }
     930             : 
     931           0 :             std::unique_ptr<out_t> err;
     932           0 :             std::unique_ptr<snap_thread> err_thread;
     933           0 :             if(mode_t::PROCESS_MODE_INOUTERR == f_mode)
     934             :             {
     935           0 :                 err.reset(new out_t(f_error));
     936           0 :                 if(err == nullptr)
     937             :                 {
     938           0 :                     return -1;
     939             :                 }
     940           0 :                 err->f_pipe = inout.f_pipes[4];
     941           0 :                 if(f_output_callback != nullptr)
     942             :                 {
     943           0 :                     err->f_callback = std::bind(&process_output_callback::error_available
     944             :                                              , f_output_callback
     945             :                                              , std::placeholders::_1
     946           0 :                                              , std::placeholders::_2);
     947             :                 }
     948           0 :                 err->f_process = this;
     949           0 :                 err_thread.reset(new snap_thread("process::error::thread", err.get()));
     950           0 :                 if(err_thread == nullptr
     951           0 :                 || !err_thread->start())
     952             :                 {
     953           0 :                     return -1;
     954             :                 }
     955             :             }
     956             : 
     957             :             // wait for the child process first
     958             :             //
     959           0 :             int const r( child.wait() );
     960             : 
     961             :             // then wait on the two or three threads
     962             :             //
     963           0 :             in_thread.stop();
     964           0 :             out_thread.stop();
     965           0 :             if(err_thread != nullptr)
     966             :             {
     967           0 :                 err_thread->stop();
     968             :             }
     969             : 
     970           0 :             return r;
     971           0 :         }
     972             :     }
     973             : }
     974             : 
     975             : 
     976             : /** \brief The input to be sent to stdin.
     977             :  *
     978             :  * Add the input data to be written to the stdin pipe. Note that the input
     979             :  * cannot be modified once the run() command was called unless the mode
     980             :  * is PROCESS_MODE_INOUT_INTERACTIVE.
     981             :  *
     982             :  * Note that in case the mode is interactive, calling this function adds
     983             :  * more data to the input. It does not erase what was added before.
     984             :  * The thread may eat some of the input in which case it gets removed
     985             :  * from the internal variable.
     986             :  *
     987             :  * \note
     988             :  * The function is safe and adding new input from the output thread
     989             :  * (which happens in interactive mode) is protected.
     990             :  *
     991             :  * \warning
     992             :  * Strings are converted to UTF-8 before getting sent to stdin. If another
     993             :  * convertion is required, make sure to use a QByteArray instead.
     994             :  *
     995             :  * \param[in] input  The input of the process (stdin).
     996             :  */
     997           0 : void process::set_input(QString const & input)
     998             : {
     999             :     // this is additive!
    1000           0 :     f_input += input.toUtf8();
    1001           0 : }
    1002             : 
    1003             : 
    1004             : /** \brief Binary data to be sent to stdin.
    1005             :  *
    1006             :  * When the input data is binary, use the QByteArray instead of a QString
    1007             :  * so you are sure it gets properly added.
    1008             :  *
    1009             :  * Calling this function multiple times appends the new data to the
    1010             :  * existing data.
    1011             :  *
    1012             :  * Please, see the other set_input() function for additional information.
    1013             :  *
    1014             :  * \note
    1015             :  * When sending a QString, remember that these are converted to UTF-8
    1016             :  * which is not compatible with purely binary data (i.e. UTF-8, for example,
    1017             :  * does not allow for 0xFE and 0xFF.)
    1018             :  *
    1019             :  * \param[in] input  The input of the process (stdin).
    1020             :  */
    1021           0 : void process::set_input(QByteArray const & input)
    1022             : {
    1023             :     // this is additive!
    1024           0 :     f_input += input;
    1025           0 : }
    1026             : 
    1027             : 
    1028             : /** \brief Read the output of the command.
    1029             :  *
    1030             :  * This function reads the output of the process. This function converts
    1031             :  * the output to UTF-8. Note that if some bytes are missing this function
    1032             :  * is likely to fail. If you are reading the data little by little as it
    1033             :  * comes in, you may want to use the get_binary_output() function
    1034             :  * instead. That way you can detect characters such as the "\n" and at
    1035             :  * that point convert the data from the previous "\n" you found in the
    1036             :  * buffer to that new "\n". This will generate valid UTF-8 strings.
    1037             :  *
    1038             :  * This function is most often used by users of commands that process
    1039             :  * one given input and generate one given output all at once.
    1040             :  *
    1041             :  * \param[in] reset  Whether the output so far should be cleared.
    1042             :  *
    1043             :  * \return The current output buffer.
    1044             :  *
    1045             :  * \sa get_binary_output()
    1046             :  */
    1047           0 : QString process::get_output(bool reset)
    1048             : {
    1049           0 :     QString const output(QString::fromUtf8(f_output));
    1050           0 :     if(reset)
    1051             :     {
    1052           0 :         f_output.clear();
    1053             :     }
    1054           0 :     return output;
    1055             : }
    1056             : 
    1057             : 
    1058             : /** \brief Read the output of the command as a binary buffer.
    1059             :  *
    1060             :  * This function reads the output of the process in binary (untouched).
    1061             :  *
    1062             :  * This function does not fail like the get_output() which attempts to
    1063             :  * convert the output of the function to UTF-8. Also the output of the
    1064             :  * command may not be UTF-8 in which case you would have to use the
    1065             :  * binary version and use a different conversion.
    1066             :  *
    1067             :  * \param[in] reset  Whether the output so far should be cleared.
    1068             :  *
    1069             :  * \return The current output buffer.
    1070             :  *
    1071             :  * \sa get_output()
    1072             :  */
    1073           0 : QByteArray process::get_binary_output(bool reset)
    1074             : {
    1075           0 :     QByteArray const output(f_output);
    1076           0 :     if(reset)
    1077             :     {
    1078           0 :         f_output.clear();
    1079             :     }
    1080           0 :     return output;
    1081             : }
    1082             : 
    1083             : 
    1084             : /** \brief Setup a callback to receive the output as it comes in.
    1085             :  *
    1086             :  * This function is used to setup a callback. That callback is expected
    1087             :  * to be called each time data arrives in our input pipe (i.e. stdout
    1088             :  * or the output pipe of the child process.)
    1089             :  *
    1090             :  * Note that if you set the process to a mode that supports the stderr
    1091             :  * pipe, then the error_available() may also get called. Otherwise,
    1092             :  * only the output_available() gets called whenever the child process
    1093             :  * generates some output.
    1094             :  *
    1095             :  * \param[in] callback  The callback class that is called on output arrival.
    1096             :  */
    1097           0 : void process::set_output_callback(process_output_callback * callback)
    1098             : {
    1099           0 :     f_output_callback = callback;
    1100           0 : }
    1101             : 
    1102             : 
    1103             : /** \brief Read the error output of the command.
    1104             :  *
    1105             :  * This function reads the error output stream of the process. This
    1106             :  * function converts the output to UTF-8. Note that if some bytes are
    1107             :  * missing this function is likely to fail. If you are reading the
    1108             :  * data little by little as it comes in, you may want to use the
    1109             :  * get_binary_output() function instead. That way you can detect
    1110             :  * characters such as the "\n" and at that point convert the data
    1111             :  * from the previous "\n" you found in the buffer to that new "\n".
    1112             :  * This will generate valid UTF-8 strings.
    1113             :  *
    1114             :  * This function is most often used when stderr is to be saved
    1115             :  * in a different file than the default.
    1116             :  *
    1117             :  * \param[in] reset  Whether the error output so far should be cleared.
    1118             :  *
    1119             :  * \return The current error output buffer.
    1120             :  *
    1121             :  * \sa get_binary_error()
    1122             :  */
    1123           0 : QString process::get_error(bool reset)
    1124             : {
    1125           0 :     QString const error(QString::fromUtf8(f_error));
    1126           0 :     if(reset)
    1127             :     {
    1128           0 :         f_error.clear();
    1129             :     }
    1130           0 :     return error;
    1131             : }
    1132             : 
    1133             : 
    1134             : /** \brief Read the error output of the command as a binary buffer.
    1135             :  *
    1136             :  * This function reads the error output of the process in binary (untouched).
    1137             :  *
    1138             :  * This function does not fail like get_error() which attempts to
    1139             :  * convert the output of the function to UTF-8. Also the error output
    1140             :  * of the command may not be UTF-8 in which case you would have to use
    1141             :  * the binary version and use a different conversion.
    1142             :  *
    1143             :  * \param[in] reset  Whether the error output so far should be cleared.
    1144             :  *
    1145             :  * \return The current error output buffer.
    1146             :  *
    1147             :  * \sa get_error()
    1148             :  */
    1149           0 : QByteArray process::get_binary_error(bool reset)
    1150             : {
    1151           0 :     QByteArray const error(f_error);
    1152           0 :     if(reset)
    1153             :     {
    1154           0 :         f_error.clear();
    1155             :     }
    1156           0 :     return error;
    1157             : }
    1158             : 
    1159             : 
    1160             : /** \brief Set the process name.
    1161             :  *
    1162             :  * This is an overload, check out the set_process_name() with char const *.
    1163             :  *
    1164             :  * \param[in] name  The new process name.
    1165             :  */
    1166           0 : void process::set_process_name(QString const & name)
    1167             : {
    1168           0 :     set_process_name(name.toUtf8().data());
    1169           0 : }
    1170             : 
    1171             : 
    1172             : /** \brief Set the process name.
    1173             :  *
    1174             :  * This is an overload, check out the set_process_name() with char const *.
    1175             :  *
    1176             :  * \param[in] name  The new process name.
    1177             :  */
    1178           0 : void process::set_process_name(std::string const & name)
    1179             : {
    1180           0 :     set_process_name(name.c_str());
    1181           0 : }
    1182             : 
    1183             : 
    1184             : /** \brief Set the process name.
    1185             :  *
    1186             :  * Whenever creating a child process (with fork() or pthread()) it is
    1187             :  * possible to change the name so tools such as `ps` or `htop` give
    1188             :  * a different name.
    1189             :  *
    1190             :  * \note
    1191             :  * The name may get truncated.
    1192             :  *
    1193             :  * \todo
    1194             :  * Look into a way to change the argv[0] as well.
    1195             :  *
    1196             :  * \param[in] name  The new name for the current process.
    1197             :  */
    1198           0 : void process::set_process_name(char const * name)
    1199             : {
    1200           0 :     if(name != nullptr
    1201           0 :     && *name != '\0')
    1202             :     {
    1203           0 :         prctl(PR_SET_NAME, name);
    1204             :     }
    1205           0 : }
    1206             : 
    1207             : 
    1208             : /** \brief Get the maximum process identifier.
    1209             :  *
    1210             :  * This function retrieves the maximum that getpid() may return.
    1211             :  *
    1212             :  * The value is cached by the function (in a static variable.) Note that
    1213             :  * is somewhat wrong since that number can be changed dynamically,
    1214             :  * although I've seen too many people ever doing so. If your process
    1215             :  * depends on it, then stop your process, make the change, and
    1216             :  * restart your process.
    1217             :  *
    1218             :  * Note that this function returns the maximum that getpid() can return
    1219             :  * and not the maximum + 1. In other words, the value returned by this
    1220             :  * function is inclusive (i.e. in most cases you will get 32767 which a
    1221             :  * process can have as its PID.)
    1222             :  *
    1223             :  * So far, the documentation I've found about the value in the kernel
    1224             :  * file is not clear about whether that value is inclusive or the
    1225             :  * last possible PID + 1. I wrote a small test to get the answer and
    1226             :  * each time the maximum PID I could get was 32767 when the content of
    1227             :  * "/proc/sys/kernel/pid_max" returns 32768. This is how most C software
    1228             :  * functions so I am pretty sure our function here is correct.
    1229             :  *
    1230             :  * \note
    1231             :  * The following code often breaks with a fork() failed error. Once
    1232             :  * you reach the rollover point, though, it cleanly stops on its own.
    1233             :  * It will print the PID just before the rollover and just after.
    1234             :  * For example, I get:
    1235             :  *
    1236             :  * \code
    1237             :  *   pid = 32765
    1238             :  *   pid = 32766
    1239             :  *   pid = 32767
    1240             :  *   pid = 301
    1241             :  * \endcode
    1242             :  *
    1243             :  * Of course, if you start this process with the smallest possible
    1244             :  * PID (such as 301) it will not stop on its own unless the fork()
    1245             :  * fails which is very likely anyway.
    1246             :  *
    1247             :  * \code
    1248             :  * int main ()
    1249             :  * {
    1250             :  *     pid_t pid;
    1251             :  * 
    1252             :  *     pid_t start = getpid();
    1253             :  *     for(int i(0);; ++i)
    1254             :  *     {
    1255             :  *         pid = fork();
    1256             :  *         if(pid == 0)
    1257             :  *         {
    1258             :  *             exit(0);
    1259             :  *         }
    1260             :  *         if(pid == -1)
    1261             :  *         {
    1262             :  *             std::cerr << "fork() failed...\n";
    1263             :  *             exit(1);
    1264             :  *         }
    1265             :  *         std::cerr << "pid = " << pid << "\n";
    1266             :  *         if(pid < start)
    1267             :  *         {
    1268             :  *             break;
    1269             :  *         }
    1270             :  *         pthread_yield();
    1271             :  *     }
    1272             :  * 
    1273             :  *     return 0;
    1274             :  * }
    1275             :  * \endcode
    1276             :  *
    1277             :  * \note
    1278             :  * We use this function in snaplock which is affected in case the
    1279             :  * parameter get dynamically changed by writing to
    1280             :  * "/proc/sys/kernel/pid_max".
    1281             :  *
    1282             :  * \return The maximum getpid() can return or -1 if it can't be determined.
    1283             :  */
    1284           0 : pid_t process::get_pid_max()
    1285             : {
    1286             :     static pid_t pid_max = 0;
    1287             : 
    1288           0 :     if(pid_max == 0)
    1289             :     {
    1290           0 :         std::ifstream in;
    1291           0 :         in.open("/proc/sys/kernel/pid_max", std::ios::in | std::ios::binary);
    1292           0 :         if(in.is_open())
    1293             :         {
    1294             :             char buf[32];
    1295           0 :             in.getline(buf, sizeof(buf) - 1);
    1296           0 :             buf[sizeof(buf) - 1] = '\0';
    1297           0 :             pid_max = std::stol(buf);
    1298             :         }
    1299             :     }
    1300             : 
    1301           0 :     return pid_max - 1;
    1302             : }
    1303             : 
    1304             : 
    1305             : 
    1306             : 
    1307             : 
    1308             : 
    1309             : 
    1310             : 
    1311             : 
    1312             : 
    1313             : /** \brief Initialize the proc_info object.
    1314             :  *
    1315             :  * This function saves the proc_t pointer and flags in this object.
    1316             :  *
    1317             :  * \exception snap_process_exception_data_not_available
    1318             :  * If the pointer p is null, the function raises this exception.
    1319             :  *
    1320             :  * \param[in] p  The proc_t pointer as returned by readproc().
    1321             :  * \param[in] flags  The set of flags from the PROCTAB used to read this data.
    1322             :  */
    1323           0 : process_list::proc_info::proc_info(std::shared_ptr<proc_t> p, int flags)
    1324             :     : f_proc(p)
    1325           0 :     , f_flags(flags)
    1326             : {
    1327           0 :     if(!f_proc)
    1328             :     {
    1329           0 :         throw snap_process_exception_data_not_available("process_list::proc_info::proc_info(): parameter p cannot be a null pointer");
    1330             :     }
    1331           0 : }
    1332             : 
    1333             : 
    1334             : /** \brief Get the process identifier.
    1335             :  *
    1336             :  * This function retrieves the process identifier of this proc_info object.
    1337             :  *
    1338             :  * \return The process identifier.
    1339             :  */
    1340           0 : pid_t process_list::proc_info::get_pid() const
    1341             : {
    1342             :     // 't' stands for 'task' which is a process or a thread
    1343           0 :     return static_cast<pid_t>(f_proc->tid);
    1344             : }
    1345             : 
    1346             : 
    1347             : /** \brief Get the parent process identifier.
    1348             :  *
    1349             :  * This function retrieves the parent process identifier of this
    1350             :  * proc_info object.
    1351             :  *
    1352             :  * \return The parent process identifier.
    1353             :  */
    1354           0 : pid_t process_list::proc_info::get_ppid() const
    1355             : {
    1356           0 :     return static_cast<pid_t>(f_proc->ppid);
    1357             : }
    1358             : 
    1359             : 
    1360             : /** \brief Get the parent process identifier.
    1361             :  *
    1362             :  * This function retrieves the parent process identifier of this
    1363             :  * proc_info object.
    1364             :  *
    1365             :  * \param[out] major  The major page fault since last update.
    1366             :  * \param[out] minor  The minor page fault since last update.
    1367             :  *
    1368             :  * \return The parent process identifier.
    1369             :  */
    1370           0 : void process_list::proc_info::get_page_faults(unsigned long & major, unsigned long & minor) const
    1371             : {
    1372           0 :     major = f_proc->maj_delta;
    1373           0 :     minor = f_proc->min_delta;
    1374           0 : }
    1375             : 
    1376             : 
    1377             : /** \brief Get the immediate percent of CPU usage for this process.
    1378             :  *
    1379             :  * This function retrieves the CPU usage as a percent of total CPU
    1380             :  * available.
    1381             :  *
    1382             :  * \return The immediate CPU usage as a percent.
    1383             :  */
    1384           0 : unsigned process_list::proc_info::get_pcpu() const
    1385             : {
    1386           0 :     return f_proc->pcpu;
    1387             : }
    1388             : 
    1389             : 
    1390             : /** \brief Get the immediate process status.
    1391             :  *
    1392             :  * This function retrieves the CPU status of the process.
    1393             :  *
    1394             :  * The status is one of the following:
    1395             :  *
    1396             :  * \li D -- uninterruptible sleep (usually I/O)
    1397             :  * \li R -- running or runnable
    1398             :  * \li S -- Sleeping
    1399             :  * \li T -- stopped by a job control signal or trace
    1400             :  * \li W -- paging (should not occur)
    1401             :  * \li X -- dead (should never appear)
    1402             :  * \li Z -- defunct zombie process
    1403             :  *
    1404             :  * \return The immediate CPU usage as a percent.
    1405             :  */
    1406           0 : char process_list::proc_info::get_status() const
    1407             : {
    1408           0 :     return f_proc->state;
    1409             : }
    1410             : 
    1411             : 
    1412             : /** \brief Get the amount of time spent by this process.
    1413             :  *
    1414             :  * This function gives you information about the four variables
    1415             :  * available cummulating the amount of time the process spent
    1416             :  * running so far.
    1417             :  *
    1418             :  * \param[out] utime  The accumulated user time of this very task.
    1419             :  * \param[out] stime  The accumulated kernel time of this very task.
    1420             :  * \param[out] cutime  The accumulated user time of this task and
    1421             :  *                     its children.
    1422             :  * \param[out] cstime  The accumulated kernel time of this task
    1423             :  *                     and its children.
    1424             :  */
    1425           0 : void process_list::proc_info::get_times(unsigned long long & utime,
    1426             :                                          unsigned long long & stime,
    1427             :                                          unsigned long long & cutime,
    1428             :                                          unsigned long long & cstime) const
    1429             : {
    1430           0 :     utime = f_proc->utime;
    1431           0 :     stime = f_proc->stime;
    1432           0 :     cutime = f_proc->cutime;
    1433           0 :     cstime = f_proc->cstime;
    1434           0 : }
    1435             : 
    1436             : 
    1437             : /** \brief Get the kernel priority of this process.
    1438             :  *
    1439             :  * This function returns the kernel priority of the process.
    1440             :  *
    1441             :  * \return The process kernel priority.
    1442             :  */
    1443           0 : long process_list::proc_info::get_priority() const
    1444             : {
    1445           0 :     return f_proc->priority;
    1446             : }
    1447             : 
    1448             : 
    1449             : /** \brief Get the unix nice of this process.
    1450             :  *
    1451             :  * This function returns the unix nice of the process.
    1452             :  *
    1453             :  * \return The process unix nice.
    1454             :  */
    1455           0 : long process_list::proc_info::get_nice() const
    1456             : {
    1457           0 :     return f_proc->nice;
    1458             : }
    1459             : 
    1460             : 
    1461             : /** \brief Get the size of this process.
    1462             :  *
    1463             :  * This function returns the total size of the process defined as
    1464             :  * the virtual memory size.
    1465             :  *
    1466             :  * \return The process total virtual size.
    1467             :  */
    1468           0 : long process_list::proc_info::get_total_size() const
    1469             : {
    1470           0 :     return f_proc->size;
    1471             : }
    1472             : 
    1473             : 
    1474             : /** \brief Get the resident size of this process.
    1475             :  *
    1476             :  * This function returns the resident total size of the process.
    1477             :  *
    1478             :  * This size represents the amount of real memory currently used by
    1479             :  * the process.
    1480             :  *
    1481             :  * \return The process resident memory size.
    1482             :  */
    1483           0 : long process_list::proc_info::get_resident_size() const
    1484             : {
    1485           0 :     return f_proc->resident;
    1486             : }
    1487             : 
    1488             : 
    1489             : /** \brief Get the process (command) name.
    1490             :  *
    1491             :  * This function return the name of the command. This includes the full
    1492             :  * path.
    1493             :  *
    1494             :  * This field is available only if field_t::COMMAND_LINE was set.
    1495             :  *
    1496             :  * \warning
    1497             :  * At this time the process does not attempt to load the `/proc/<pid>/status`
    1498             :  * file and as a result the process name may end up being empty because
    1499             :  * it was not defined in the command line (this is done quite a bit with
    1500             :  * kernel processes.)
    1501             :  *
    1502             :  * \return The process name.
    1503             :  */
    1504           0 : std::string process_list::proc_info::get_process_name() const
    1505             : {
    1506           0 :     if((f_flags & (PROC_FILLCOM | PROC_FILLARG)) == 0)
    1507             :     {
    1508           0 :         throw snap_process_exception_data_not_available("process_list::proc_info::get_process_name(): data not available");
    1509             :     }
    1510             : 
    1511           0 :     if(f_proc->cmdline == nullptr)
    1512             :     {
    1513           0 :         return std::string();
    1514             :     }
    1515             : 
    1516           0 :     return f_proc->cmdline[0];
    1517             : }
    1518             : 
    1519             : 
    1520             : /** \brief Get the process (command) basename.
    1521             :  *
    1522             :  * By default, the process name is the full name used on the command line
    1523             :  * to start this process. If that was a full path, then the full pass is
    1524             :  * included in the process name.
    1525             :  *
    1526             :  * This function returns the basename only.
    1527             :  *
    1528             :  * This field is available only if field_t::COMMAND_LINE was set.
    1529             :  *
    1530             :  * \return The process name.
    1531             :  */
    1532           0 : std::string process_list::proc_info::get_process_basename() const
    1533             : {
    1534           0 :     std::string const name(get_process_name());
    1535             : 
    1536           0 :     std::string::size_type const pos(name.rfind('/'));
    1537           0 :     if(pos == std::string::npos)
    1538             :     {
    1539             :         // no '/' so there was no path, return name as is
    1540             :         //
    1541           0 :         return name;
    1542             :     }
    1543             : 
    1544             :     // there is a slash, remove everything before that slash
    1545             :     // and the slash itself
    1546             :     //
    1547           0 :     return name.substr(pos + 1);
    1548             : }
    1549             : 
    1550             : 
    1551             : /** \brief Get the number of arguments defined on the command line.
    1552             :  *
    1553             :  * This function counts the number of arguments, including all the many
    1554             :  * empty arguments.
    1555             :  *
    1556             :  * Count will be positive or null. The count does not include the command
    1557             :  * line (program name.)
    1558             :  *
    1559             :  * \return Count the number of arguments.
    1560             :  *
    1561             :  * \sa get_arg()
    1562             :  */
    1563           0 : int process_list::proc_info::get_args_size() const
    1564             : {
    1565           0 :     if(f_count == -1)
    1566             :     {
    1567           0 :         char ** s(f_proc->cmdline);
    1568           0 :         if(s != nullptr)
    1569             :         {
    1570           0 :             while(*s != nullptr)
    1571             :             {
    1572           0 :                 ++s;
    1573             :             }
    1574           0 :             f_count = static_cast<int32_t>(s - f_proc->cmdline - 1);
    1575             :         }
    1576           0 :         if(f_count < 0)
    1577             :         {
    1578             :             // it could be negative if we could not even get the command
    1579             :             // line program name (in most cases: permission denied)
    1580           0 :             f_count = 0;
    1581             :         }
    1582             :     }
    1583             : 
    1584           0 :     return f_count;
    1585             : }
    1586             : 
    1587             : 
    1588             : /** \brief Get the argument at the specified index.
    1589             :  *
    1590             :  * This function returns one of the arguments of the command line of
    1591             :  * this process. Note that very often arguments are empty strings.
    1592             :  *
    1593             :  * \param[in] index  The index of the argument to retrieve.
    1594             :  *
    1595             :  * \return The specified argument.
    1596             :  *
    1597             :  * \sa get_args_size()
    1598             :  */
    1599           0 : std::string process_list::proc_info::get_arg(int index) const
    1600             : {
    1601             :     // the number of arguments must be gathered first: see get_args_size()
    1602             :     // that other function defines the `f_count` parameter which then
    1603             :     // won't be -1, although it could still be zero and prevent a call
    1604             :     // to this function
    1605             :     //
    1606           0 :     if(f_count == -1)
    1607             :     {
    1608             :         // I use a logic exception because I think this one should never
    1609             :         // happen, if a programmer gets this error, he/she needs to fix
    1610             :         // his/her code immediately
    1611             :         //
    1612           0 :         throw snap_logic_exception("process_list::proc_info::get_arg(): get_arg() cannot be called before get_args_size().");
    1613             :     }
    1614             : 
    1615           0 :     if(static_cast<uint32_t>(index) >= static_cast<uint32_t>(f_count))
    1616             :     {
    1617           0 :         throw snap_process_exception_data_not_available(QString("process_list::proc_info::get_arg(): index %1 is larger than f_count %1").arg(index).arg(f_count));
    1618             :     }
    1619             : 
    1620           0 :     return f_proc->cmdline[index + 1];
    1621             : }
    1622             : 
    1623             : 
    1624             : /** \brief Get the controlling terminal of this process.
    1625             :  *
    1626             :  * This function returns the full device number of the
    1627             :  * controlling terminal.
    1628             :  *
    1629             :  * \return The number of the process controlling terminal.
    1630             :  */
    1631           0 : int process_list::proc_info::get_tty() const
    1632             : {
    1633           0 :     return f_proc->resident;
    1634             : }
    1635             : 
    1636             : 
    1637             : /** \brief Convert a field number to a process flag.
    1638             :  *
    1639             :  * This function converts a field number to a process flag.
    1640             :  *
    1641             :  * \li field_t::MEMORY -- get the various memory fields.
    1642             :  * \li field_t::STATUS -- retrieve the current status of the process
    1643             :  * such as 'R' for running and 'S' for sleeping.
    1644             :  * \li field_t::STATISTICS -- read the variable statistics.
    1645             :  * \li field_t::WAIT_CHANNEL -- kernel wait channel.
    1646             :  * \li field_t::COMMAND_LINE -- command line with arguments.
    1647             :  * \li field_t::ENVIRON -- environment at the time the process started.
    1648             :  * \li field_t::USER_NAME -- user name owner of the process.
    1649             :  * \li field_t::GROUP_NAME -- group name owner of the process.
    1650             :  * \li field_t::CONTROL_GROUPS -- list of control groups.
    1651             :  * \li field_t::SUPPLEMENTARY_GROUPS -- supplementary groups.
    1652             :  * \li field_t::OUT_OF_MEMORY -- information about various OOM events.
    1653             :  * \li field_t::NAMESPACE -- process namespace (to hide sub-pids.)
    1654             :  *
    1655             :  * \param[in] fld  The field number to convert.
    1656             :  *
    1657             :  * \return The PROC_... flag corresponding to the specified field.
    1658             :  */
    1659           0 : int process_list::field_to_flag(field_t fld) const
    1660             : {
    1661           0 :     switch(fld)
    1662             :     {
    1663           0 :     case field_t::MEMORY:
    1664           0 :         return PROC_FILLMEM;
    1665             : 
    1666           0 :     case field_t::STATUS:
    1667           0 :         return PROC_FILLSTATUS;
    1668             : 
    1669           0 :     case field_t::STATISTICS:
    1670           0 :         return PROC_FILLSTAT;
    1671             : 
    1672           0 :     case field_t::WAIT_CHANNEL:
    1673             : #ifdef PROC_FILLWCHAN
    1674             :         // in version 6, this was removed
    1675             :         return PROC_FILLWCHAN;
    1676             : #else
    1677           0 :         break;
    1678             : #endif
    1679             : 
    1680           0 :     case field_t::COMMAND_LINE:
    1681           0 :         return PROC_FILLCOM | PROC_FILLARG;
    1682             : 
    1683           0 :     case field_t::ENVIRON:
    1684           0 :         return PROC_FILLENV;
    1685             : 
    1686           0 :     case field_t::USER_NAME:
    1687           0 :         return PROC_FILLUSR;
    1688             : 
    1689           0 :     case field_t::GROUP_NAME:
    1690           0 :         return PROC_FILLGRP;
    1691             : 
    1692           0 :     case field_t::CGROUP:
    1693           0 :         return PROC_FILLCGROUP;
    1694             : 
    1695           0 :     case field_t::SUPPLEMENTARY_GROUP:
    1696           0 :         return PROC_FILLSUPGRP;
    1697             : 
    1698           0 :     case field_t::OOM:
    1699           0 :         return PROC_FILLOOM;
    1700             : 
    1701           0 :     case field_t::NAMESPACE:
    1702           0 :         return PROC_FILLNS;
    1703             : 
    1704             :     }
    1705           0 :     throw snap_process_exception_unknown_flag("process_list::field_to_flag(): invalid field number");
    1706             : }
    1707             : 
    1708             : 
    1709             : /** \brief Check whether a field was set or cleared.
    1710             :  *
    1711             :  * \param[in] fld  The field to check.
    1712             :  *
    1713             :  * \return true if the field was set, false otherwise.
    1714             :  */
    1715           0 : bool process_list::get_field(field_t fld) const
    1716             : {
    1717           0 :     return (f_flags & field_to_flag(fld)) != 0;
    1718             : }
    1719             : 
    1720             : 
    1721             : /** \brief Set a field.
    1722             :  *
    1723             :  * Set the flag so the specified field(s) get loaded on calls to the next()
    1724             :  * function.
    1725             :  *
    1726             :  * This function must be called once per field group you are interested in.
    1727             :  *
    1728             :  * Note that each field corresponds to a file in the /proc file system.
    1729             :  * It is smart to really only get those that you really need.
    1730             :  *
    1731             :  * \param[in] fld  The field to set.
    1732             :  */
    1733           0 : void process_list::set_field(field_t fld)
    1734             : {
    1735           0 :     if(f_proctab)
    1736             :     {
    1737           0 :         throw snap_process_exception_already_initialized("process_list::set_flag(): process flags cannot be set after next() was called");
    1738             :     }
    1739           0 :     f_flags |= field_to_flag(fld);
    1740           0 : }
    1741             : 
    1742             : 
    1743             : /** \brief Clear a field.
    1744             :  *
    1745             :  * Clear the flag so the specified field(s) do NOT get loaded on calls to
    1746             :  * the next() function.
    1747             :  *
    1748             :  * This function can be used to reset fields that were previously set
    1749             :  * with the set_field() function.
    1750             :  *
    1751             :  * \param[in] fld  The field to clear.
    1752             :  */
    1753           0 : void process_list::clear_field(field_t fld)
    1754             : {
    1755           0 :     if(f_proctab)
    1756             :     {
    1757           0 :         throw snap_process_exception_already_initialized("process_list::set_flag(): process flags cannot be reset after next() was called");
    1758             :     }
    1759           0 :     f_flags &= ~field_to_flag(fld);
    1760           0 : }
    1761             : 
    1762             : 
    1763             : /** \brief Reset the listing of processes.
    1764             :  *
    1765             :  * This function reset the list of processes by clearing the internal
    1766             :  * pointer to the PROCTAB object.
    1767             :  *
    1768             :  * This can be called at any time.
    1769             :  *
    1770             :  * After a call to rewind() you may change the sets of flags with calls
    1771             :  * to set_field() and clear_field().
    1772             :  */
    1773           0 : void process_list::rewind()
    1774             : {
    1775           0 :     f_proctab.reset();
    1776           0 : }
    1777             : 
    1778             : 
    1779             : /** \brief Read the next process.
    1780             :  *
    1781             :  * This function reads the information about the next process and
    1782             :  * returns it in a shared pointer. The shared pointer can simply
    1783             :  * be destroyed to release any memory allocated by the process_list
    1784             :  * object.
    1785             :  *
    1786             :  * The object returned holds a pointer to the proc_t data
    1787             :  * as read by the readproc() function. You can find this structure
    1788             :  * and additional information in /usr/include/proc/readproc.h (assuming
    1789             :  * you have the libprocps3-dev package installed.)
    1790             :  *
    1791             :  * \return A shared pointer to a proc_t structure.
    1792             :  */
    1793           0 : process_list::proc_info::pointer_t process_list::next()
    1794             : {
    1795             :     struct deleters
    1796             :     {
    1797           0 :         static void delete_proctab(PROCTAB * ptr)
    1798             :         {
    1799           0 :             if(ptr != nullptr)
    1800             :             {
    1801           0 :                 closeproc(ptr);
    1802             :             }
    1803           0 :         }
    1804             : 
    1805           0 :         static void delete_proc(proc_t * ptr)
    1806             :         {
    1807           0 :             if(ptr != nullptr)
    1808             :             {
    1809           0 :                 freeproc(ptr);
    1810             :             }
    1811           0 :         }
    1812             :     };
    1813             : 
    1814           0 :     if(!f_proctab)
    1815             :     {
    1816           0 :         f_proctab.reset(openproc(f_flags, 0, 0), deleters::delete_proctab);
    1817           0 :         if(!f_proctab)
    1818             :         {
    1819           0 :             throw snap_process_exception_openproc("process_list::next(): openproc() failed opening \"proc\", cannot read processes.");
    1820             :         }
    1821             :     }
    1822             : 
    1823             :     // I tested and if readproc() is called again after returning nullptr, it
    1824             :     // continues to return nullptr so no need to do anything more
    1825             :     //
    1826           0 :     std::shared_ptr<proc_t> p; // use reset(), see SNAP-507
    1827           0 :     p.reset(readproc(f_proctab.get(), nullptr), deleters::delete_proc);
    1828           0 :     if(p)
    1829             :     {
    1830           0 :         return proc_info::pointer_t(new proc_info(p, f_flags));
    1831             :     }
    1832             : 
    1833           0 :     return proc_info::pointer_t();
    1834             : }
    1835             : 
    1836             : 
    1837           6 : } // namespace snap
    1838             : 
    1839             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.13