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
|