Line data Source code
1 : // Copyright (c) 2013-2021 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/eventdispatcher
4 : // contact@m2osw.com
5 : //
6 : // This program is free software; you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation; either version 2 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License along
17 : // with this program; if not, write to the Free Software Foundation, Inc.,
18 : // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 :
20 :
21 : // self
22 : //
23 : #include "cppprocess/process.h"
24 :
25 : #include "cppprocess/exception.h"
26 :
27 :
28 : // eventdispatcher lib
29 : //
30 :
31 :
32 : // snaplogger lib
33 : //
34 : #include <snaplogger/message.h>
35 :
36 :
37 : // snapdev lib
38 : //
39 : #include <snapdev/glob_to_list.h>
40 : #include <snapdev/join_strings.h>
41 : #include <snapdev/trim_string.h>
42 : #include <snapdev/not_reached.h>
43 :
44 :
45 : // C lib
46 : //
47 : #include <fcntl.h>
48 : #include <string.h>
49 : #include <signal.h>
50 :
51 :
52 : // last include
53 : //
54 : #include <snapdev/poison.h>
55 :
56 :
57 :
58 :
59 :
60 : extern char ** environ;
61 :
62 : namespace cppprocess
63 : {
64 :
65 :
66 :
67 : namespace
68 : {
69 :
70 :
71 :
72 :
73 3 : class direct_input_data
74 : : public ed::pipe_connection
75 : {
76 : public:
77 : direct_input_data(process * p, buffer_t const & input);
78 : direct_input_data(direct_input_data const &) = delete;
79 : direct_input_data & operator = (direct_input_data const &) = delete;
80 :
81 : // pipe_connection implementation
82 : //
83 : virtual bool is_writer() const override;
84 : virtual void process_write() override;
85 :
86 : virtual void process_error() override;
87 : virtual void process_invalid() override;
88 : virtual void process_hup() override;
89 :
90 : private:
91 : process * f_process = nullptr;
92 : buffer_t const & f_input;
93 : std::size_t f_pos = 0;
94 : };
95 :
96 :
97 3 : direct_input_data::direct_input_data(process * p, buffer_t const & input)
98 : : pipe_connection(ed::pipe_t::PIPE_CHILD_INPUT)
99 : , f_process(p)
100 3 : , f_input(input)
101 : {
102 3 : set_name("direct_input_data");
103 3 : }
104 :
105 :
106 3 : bool direct_input_data::is_writer() const
107 : {
108 3 : return f_pos < f_input.size();
109 : }
110 :
111 :
112 3 : void direct_input_data::process_write()
113 : {
114 3 : std::size_t const size(f_input.size() - f_pos);
115 3 : if(size > 0)
116 : {
117 3 : ssize_t const r(write(f_input.data() + f_pos, size));
118 3 : if(r > 0)
119 : {
120 3 : f_pos += r;
121 :
122 3 : if(f_pos >= f_input.size())
123 : {
124 3 : f_process->input_pipe_done();
125 : }
126 : }
127 : }
128 3 : }
129 :
130 :
131 0 : void direct_input_data::process_error()
132 : {
133 0 : f_process->input_pipe_done();
134 0 : }
135 :
136 :
137 0 : void direct_input_data::process_invalid()
138 : {
139 0 : f_process->input_pipe_done();
140 0 : }
141 :
142 :
143 0 : void direct_input_data::process_hup()
144 : {
145 0 : f_process->input_pipe_done();
146 0 : }
147 :
148 :
149 :
150 :
151 :
152 :
153 :
154 :
155 :
156 : /** \brief A direct output to input pipe.
157 : *
158 : * When piping one command to another, then this pipe object gets used.
159 : * This pipe directly sends the output of the previous command to the
160 : * input of the next command.
161 : *
162 : * Internally, we may also use the tee_pipe which sends the output of
163 : * the previous command to the input of all the next commands.
164 : */
165 2 : class direct_output_to_input_pipe
166 : : public ed::pipe_connection
167 : {
168 : public:
169 : direct_output_to_input_pipe();
170 :
171 : // pipe_connection implementation
172 : //
173 : virtual void forked() override;
174 :
175 : private:
176 : };
177 :
178 :
179 2 : direct_output_to_input_pipe::direct_output_to_input_pipe()
180 2 : : pipe_connection(ed::pipe_t::PIPE_CHILD_OUTPUT)
181 : {
182 2 : set_name("direct_output_to_input_pipe");
183 2 : }
184 :
185 :
186 2 : void direct_output_to_input_pipe::forked()
187 : {
188 : // force a full close in this case
189 : //
190 2 : close();
191 2 : }
192 :
193 :
194 :
195 :
196 :
197 :
198 :
199 4 : class capture_output_pipe
200 : : public ed::pipe_connection
201 : {
202 : public:
203 : capture_output_pipe(process * p, buffer_t & output);
204 : capture_output_pipe(capture_output_pipe const &) = delete;
205 : capture_output_pipe & operator = (capture_output_pipe const &) = delete;
206 :
207 : // pipe_connection implementation
208 : //
209 : virtual void process_read() override;
210 :
211 : virtual void process_error() override;
212 : virtual void process_invalid() override;
213 : virtual void process_hup() override;
214 :
215 : private:
216 : process * f_process = nullptr;
217 : buffer_t & f_output;
218 : };
219 :
220 :
221 4 : capture_output_pipe::capture_output_pipe(process * p, buffer_t & output)
222 : : pipe_connection(ed::pipe_t::PIPE_CHILD_OUTPUT)
223 : , f_process(p)
224 4 : , f_output(output)
225 : {
226 4 : set_name("capture_output_pipe");
227 4 : }
228 :
229 :
230 5 : void capture_output_pipe::process_read()
231 : {
232 5 : if(get_socket() != -1)
233 : {
234 : // handle up to 64Kb at once
235 : //
236 5 : char buffer[1'024 * 64];
237 5 : errno = 0;
238 5 : ssize_t const r(read(&buffer[0], sizeof(buffer)));
239 5 : if(r < 0
240 0 : && errno != 0
241 0 : && errno != EAGAIN
242 0 : && errno != EWOULDBLOCK)
243 : {
244 0 : int const e(errno);
245 0 : SNAP_LOG_ERROR
246 0 : << "an error occurred while reading from pipe (errno: "
247 : << e
248 : << " -- "
249 0 : << strerror(e)
250 : << ")."
251 : << SNAP_LOG_SEND;
252 0 : process_error();
253 0 : return;
254 : }
255 :
256 5 : if(r > 0)
257 : {
258 : // append to output buffer
259 : //
260 5 : f_output.insert(f_output.end(), buffer, buffer + r);
261 : }
262 : }
263 :
264 : // process the next level
265 : //
266 5 : pipe_connection::process_read();
267 : }
268 :
269 :
270 0 : void capture_output_pipe::process_error()
271 : {
272 0 : f_process->output_pipe_done(this);
273 0 : }
274 :
275 :
276 0 : void capture_output_pipe::process_invalid()
277 : {
278 0 : f_process->output_pipe_done(this);
279 0 : }
280 :
281 :
282 4 : void capture_output_pipe::process_hup()
283 : {
284 4 : f_process->output_pipe_done(this);
285 4 : }
286 :
287 :
288 :
289 :
290 :
291 :
292 :
293 0 : class buffered_pipe
294 : : public ed::pipe_connection
295 : {
296 : public:
297 : buffered_pipe();
298 :
299 : // connection
300 : virtual bool is_writer() const override;
301 :
302 : // pipe implementation
303 : virtual ssize_t write(void const * data, size_t length) override;
304 : virtual void process_write() override;
305 : virtual void process_hup() override;
306 :
307 : private:
308 : std::vector<char> f_output = std::vector<char>();
309 : size_t f_position = 0;
310 : };
311 :
312 :
313 0 : buffered_pipe::buffered_pipe()
314 0 : : pipe_connection(ed::pipe_t::PIPE_CHILD_OUTPUT)
315 : {
316 0 : set_name("buffered_pipe");
317 0 : }
318 :
319 :
320 0 : bool buffered_pipe::is_writer() const
321 : {
322 0 : return get_socket() != -1 && !f_output.empty();
323 : }
324 :
325 :
326 0 : ssize_t buffered_pipe::write(void const * data, size_t length)
327 : {
328 0 : if(get_socket() == -1)
329 : {
330 0 : errno = EBADF;
331 0 : return -1;
332 : }
333 :
334 0 : if(data != nullptr && length > 0)
335 : {
336 0 : char const * d(reinterpret_cast<char const *>(data));
337 0 : f_output.insert(f_output.end(), d, d + length);
338 0 : return length;
339 : }
340 :
341 0 : return 0;
342 : }
343 :
344 :
345 0 : void buffered_pipe::process_write()
346 : {
347 0 : if(get_socket() != -1)
348 : {
349 0 : errno = 0;
350 0 : ssize_t const r(pipe_connection::write(&f_output[f_position], f_output.size() - f_position));
351 0 : if(r > 0)
352 : {
353 : // some data was written
354 : //
355 0 : f_position += r;
356 0 : if(f_position >= f_output.size())
357 : {
358 0 : f_output.clear();
359 0 : f_position = 0;
360 0 : process_empty_buffer();
361 : }
362 : }
363 0 : else if(r != 0 && errno != 0 && errno != EAGAIN && errno != EWOULDBLOCK)
364 : {
365 : // connection is considered bad, get rid of it
366 : //
367 0 : int const e(errno);
368 0 : SNAP_LOG_ERROR
369 0 : << "an error occurred while writing to socket of \""
370 0 : << get_name()
371 0 : << "\" (errno: "
372 : << e
373 : << " -- "
374 0 : << strerror(e)
375 : << ")."
376 : << SNAP_LOG_SEND;
377 0 : process_error();
378 0 : return;
379 : }
380 : }
381 : //else -- TBD: should we generate an error when the socket is not valid?
382 :
383 : // process next level too
384 : //
385 0 : pipe_connection::process_write();
386 : }
387 :
388 :
389 0 : void buffered_pipe::process_hup()
390 : {
391 0 : close();
392 :
393 0 : pipe_connection::process_hup();
394 0 : }
395 :
396 :
397 :
398 :
399 :
400 :
401 :
402 0 : class tee_pipe
403 : : public ed::pipe_connection
404 : {
405 : public:
406 : tee_pipe(std::size_t const size);
407 :
408 : ed::pipe_connection::pointer_t get_output_pipe(std::size_t idx);
409 :
410 : // pipe_connection
411 : //
412 : virtual void process_read() override;
413 : virtual void connection_added() override;
414 : virtual void connection_removed() override;
415 :
416 : private:
417 : ed::communicator::pointer_t f_communicator = ed::communicator::pointer_t();
418 : ed::pipe_connection::vector_t f_output = ed::pipe_connection::vector_t();
419 : };
420 :
421 :
422 0 : tee_pipe::tee_pipe(std::size_t const size)
423 : : pipe_connection(ed::pipe_t::PIPE_CHILD_INPUT)
424 : , f_communicator(ed::communicator::instance())
425 0 : , f_output(size)
426 : {
427 0 : set_name("tee_pipe");
428 :
429 0 : if(size == 0)
430 : {
431 0 : throw cppprocess_logic_error("tee_pipe constructor called with a size of zero is not supported");
432 : }
433 :
434 0 : for(std::size_t idx(0); idx < size; ++idx)
435 : {
436 0 : f_output[idx] = std::make_shared<buffered_pipe>();
437 : }
438 0 : }
439 :
440 :
441 0 : ed::pipe_connection::pointer_t tee_pipe::get_output_pipe(std::size_t idx)
442 : {
443 0 : if(idx >= f_output.size())
444 : {
445 : throw cppprocess_out_of_range(
446 : "get_output_pipe() called with index "
447 0 : + std::to_string(idx)
448 0 : + ", which is out of allowed range: [0.."
449 0 : + std::to_string(f_output.size())
450 0 : + ").");
451 : }
452 :
453 0 : return f_output[idx];
454 : }
455 :
456 :
457 0 : void tee_pipe::process_read()
458 : {
459 0 : if(get_socket() != -1)
460 : {
461 : // handle up to 64Kb at once
462 : //
463 0 : char buffer[1'024 * 64];
464 0 : errno = 0;
465 0 : ssize_t const r(read(&buffer[0], sizeof(buffer)));
466 0 : if(r < 0
467 0 : && errno != 0
468 0 : && errno != EAGAIN
469 0 : && errno != EWOULDBLOCK)
470 : {
471 : // this happens all the time (i.e. another process quits)
472 : // so we make it a debug and not a warning or an error...
473 : //
474 0 : int const e(errno);
475 0 : SNAP_LOG_DEBUG
476 0 : << "an error occurred while reading from socket (errno: "
477 : << e
478 : << " -- "
479 0 : << strerror(e)
480 : << ")."
481 : << SNAP_LOG_SEND;
482 0 : process_error();
483 0 : return;
484 : }
485 :
486 0 : if(r > 0)
487 : {
488 : // this is the T functionality, where we duplicate the data in
489 : // the input of each of the succeeded processes
490 : //
491 0 : for(auto & out : f_output)
492 : {
493 0 : out->write(&buffer[0], r);
494 : }
495 : }
496 : }
497 :
498 : // process the next level
499 : //
500 0 : pipe_connection::process_read();
501 : }
502 :
503 :
504 0 : void tee_pipe::connection_added()
505 : {
506 0 : for(auto & out : f_output)
507 : {
508 0 : f_communicator->add_connection(out);
509 : }
510 0 : }
511 :
512 :
513 0 : void tee_pipe::connection_removed()
514 : {
515 0 : for(auto & out : f_output)
516 : {
517 0 : f_communicator->remove_connection(out);
518 : }
519 0 : }
520 :
521 :
522 :
523 : } // no name namespace
524 :
525 :
526 :
527 :
528 : /** \class process
529 : * \brief A process class to run a process and get information about the results.
530 : *
531 : * This class is used to run processes. Especially, it can run with in and
532 : * out capabilities (i.e. piping) although this is generally not recommanded
533 : * because piping can block (if you do not send enough data, or do not read
534 : * enough data, then the pipes can get stuck.) We use a thread to read the
535 : * results. We do not currently expect that the use of this class will require
536 : * the input read to be necessary to know what needs to be written (i.e. in
537 : * most cases all we want is to convert a file [input] from one format to
538 : * another [output] avoiding reading/writing on disk.)
539 : *
540 : * The whole process, when using the interactive mode, is quite complicated
541 : * so I wrote the following diagram. As you can see, the loop of sending
542 : * and receiving data from the child process is fairly simple. Note that the
543 : * callback is called from the Output Thread, not the main process. This does
544 : * not make much of a difference because no other function can be running on
545 : * the main process when that happens. The output is blocked and thus the
546 : * output variable is safe. The input is not blocked but adding input was
547 : * made safe internally.
548 : *
549 : * \msc
550 : * hscale = "2";
551 : * a [label="Function"],b [label="Process"],c [label="Input Thread"],d [label="Output Thread"],e [label="Child Process"];
552 : *
553 : * a=>b [label="run()"];
554 : * b=>e [label="fork()"];
555 : * e->e [label="execvpe()"];
556 : * b=>c [label="pthread_create()"];
557 : * b=>d [label="pthread_create()"];
558 : * b=>e [label="wait() child's death"];
559 : *
560 : * --- [label="start repeat"];
561 : * c->e [label="write() (Input Data)"];
562 : * d<-e [label="read() (Output Data)"];
563 : * b<:d [label="output shared"];
564 : * a<<=d [label="output callback"];
565 : * a=>b [label="set_input()"];
566 : * b=>c [label="add input"];
567 : * --- [label="end repeat"];
568 : *
569 : * b<-e [label="child died"];
570 : * b->c [label="stop()"];
571 : * b<-c [label="stopped"];
572 : * b->d [label="stop()"];
573 : * b<-d [label="stopped"];
574 : * a<\<b [label="run()"];
575 : * \endmsc
576 : *
577 : * Using the add_next_process function, it is possible to pipe the output
578 : * of one process as the input of the next process. In other words, this
579 : * class allows you to pipe any number of processes between each other.
580 : *
581 : * \code
582 : * cppprocess:process a;
583 : * cppprocess:process b;
584 : * cppprocess:process c;
585 : *
586 : * a.set_next_process(b);
587 : * b.set_next_process(c);
588 : *
589 : * a.start(); // runs `a | b | c`
590 : * \endcode
591 : *
592 : * When piping processes in this way, pipes are used and the more powerful
593 : * scheme is used (fork() + execvpe() instead of a simpler popen() or even
594 : * a system() call).
595 : *
596 : * Also, when piping processes, you can only add one input pipe to the
597 : * very first process and one output pipe to the very last process. You
598 : * can, however, add one error pipe to each process (i.e. so you can know
599 : * which process output such and such errors).
600 : *
601 : * When piping processes, you only call the start() function of
602 : * the first process. That will have the side effect of starting all the
603 : * following processes as expected.
604 : *
605 : * The feature includes a "tee" feature, which allows you to pipe the
606 : * output of one process as the input of any number of processes. This
607 : * is done by adding multiple processes as the next process of one
608 : * proces.
609 : *
610 : * \code
611 : * cppprocess:process a;
612 : * cppprocess:process b;
613 : * cppprocess:process c;
614 : * cppprocess:process c;
615 : *
616 : * a.set_next_process(b);
617 : * a.set_next_process(c);
618 : * a.set_next_process(d);
619 : *
620 : * a.start();
621 : *
622 : * // equivalent to:
623 : * // a > data.tmp
624 : * // b < data.tmp
625 : * // c < data.tmp
626 : * // d < data.tmp
627 : * // only we avoid the temporary file and b, c, d are run in parallel
628 : * // note that b, c, d could be the same process with different args
629 : * \endcode
630 : */
631 :
632 :
633 : /** \brief Initialize the process object.
634 : *
635 : * This function saves the name of the process. The name is generally a
636 : * static string and it is used to distinguish between processes when
637 : * managing several at once. The function makes a copy of the name.
638 : *
639 : * \note
640 : * The name of the process is not the command. See set_command().
641 : *
642 : * \param[in] name The name of the process.
643 : *
644 : * \sa set_command()
645 : * \sa get_name()
646 : */
647 8 : process::process(std::string const & name)
648 : : f_communicator(ed::communicator::instance())
649 8 : , f_name(name)
650 : {
651 8 : }
652 :
653 :
654 : /** \brief Retrieve the name of this process object.
655 : *
656 : * This process object is given a name on creation. In most cases this is
657 : * a static name that is used to determine which process is which.
658 : *
659 : * \return The name of the process.
660 : */
661 4 : std::string const & process::get_name() const
662 : {
663 4 : return f_name;
664 : }
665 :
666 :
667 : /** \brief Set how the environment variables are defined in the process.
668 : *
669 : * By default all of the current process environment variables are
670 : * passed to the child process. If the child process is not 100% trustworthy,
671 : * it may be preferable to only pass a specific set of environment variables
672 : * (as added by the add_environ() function) to the child process.
673 : *
674 : * This function sets a flag to determine whether we want to force the
675 : * environment (true) to the list of variables added with the
676 : * add_environ() function or let our current process variables
677 : * flow through (false, the default).
678 : *
679 : * \param[in] forced Whether the environment will be forced.
680 : *
681 : * \sa add_environ()
682 : * \sa get_forced_environment()
683 : */
684 4 : void process::set_forced_environment(bool forced)
685 : {
686 4 : f_forced_environment = forced;
687 4 : }
688 :
689 :
690 : /** \brief Check the current status of the forced environment flag.
691 : *
692 : * This function returns a copy of the forced environment flag. If true,
693 : * then the run() function will force the environment variables as
694 : * defined by add_environ() function instead of all the environment
695 : * variables of the calling process.
696 : *
697 : * \return The status of the forced environment flag.
698 : *
699 : * \sa add_environ()
700 : * \sa set_forced_environment()
701 : */
702 6 : bool process::get_forced_environment() const
703 : {
704 6 : return f_forced_environment;
705 : }
706 :
707 :
708 : /** \brief Define the command to run.
709 : *
710 : * The command name may be a full path or just the command filename.
711 : * (i.e. the `execvp()` function makes use of the PATH variable to find
712 : * the command on disk unless the \p command parameter includes a
713 : * slash character.)
714 : *
715 : * \warning
716 : * Do not add any arguments here. Instead, make sure to use the
717 : * add_argument() to add any number of arguments.
718 : *
719 : * If the process cannot be found, an error is generated at the time you
720 : * call the run() function.
721 : *
722 : * \param[in] command The command to start the new process.
723 : *
724 : * \sa add_argument()
725 : * \sa get_command()
726 : */
727 8 : void process::set_command(std::string const & command)
728 : {
729 8 : f_command = command;
730 8 : }
731 :
732 :
733 : /** \brief Retrieve the command name & path.
734 : *
735 : * This function returns the command as set with the set_command() function.
736 : *
737 : * If the set_command() was never called, then the command is the
738 : * empty string at this point.
739 : *
740 : * \return The command name and path (the path is optional).
741 : *
742 : * \sa set_command()
743 : */
744 7 : std::string const & process::get_command() const
745 : {
746 7 : return f_command;
747 : }
748 :
749 :
750 : /** \brief Add an argument to the command line.
751 : *
752 : * This function adds one individual arguement to the command line.
753 : *
754 : * You have to add all the arguments in the right order.
755 : *
756 : * If you set the \p expand flag to true, then the function transforms the
757 : * argument into a list of file names and add those instead. If the
758 : * argument does not match any filename, then it is added as is.
759 : *
760 : * If the expansion fails, then the function prints out an error message
761 : * in the log and it returns false.
762 : *
763 : * \param[in] arg The argument to be added.
764 : * \param[in] expand Whether this argument includes glob characters to expand.
765 : *
766 : * \return true if the argument was added without issue.
767 : *
768 : * \sa get_arguments()
769 : */
770 11 : bool process::add_argument(std::string const & arg, bool expand)
771 : {
772 11 : if(!expand)
773 : {
774 11 : f_arguments.push_back(arg);
775 11 : return true;
776 : }
777 :
778 0 : if(!f_arguments.read_path<
779 : snap::glob_to_list_flag_t::GLOB_FLAG_BRACE
780 : , snap::glob_to_list_flag_t::GLOB_FLAG_PERIOD
781 0 : , snap::glob_to_list_flag_t::GLOB_FLAG_TILDE>(arg))
782 : {
783 0 : SNAP_LOG_ERROR
784 0 : << "an error occurred reading argument filenames from pattern \""
785 : << arg
786 : << "\": "
787 0 : << f_arguments.get_last_error_message()
788 0 : << " (errno: "
789 : << f_arguments.get_last_error_errno()
790 : << ", "
791 0 : << strerror(f_arguments.get_last_error_errno())
792 : << ")."
793 : << SNAP_LOG_SEND;
794 0 : return false;
795 : }
796 :
797 0 : return true;
798 : }
799 :
800 :
801 : /** \brief Return the current list of updatable arguments.
802 : *
803 : * This function returns a non-constant reference to the list of arguments
804 : * currently available in this process.
805 : *
806 : * This gives you the ability to go through the list and make changes.
807 : * This is often used when you want to run the same command with different
808 : * parameters (i.e. maybe a filename that changes between runs).
809 : *
810 : * It is important to keep in mind that if you expanded an argument, the
811 : * list may now include from 0 to any number of arguments as a replacement
812 : * to that one expanded argument.
813 : *
814 : * \return The list of arguments attached to this process.
815 : *
816 : * \sa add_argument()
817 : */
818 6 : process::argument_list_t & process::get_arguments()
819 : {
820 6 : return f_arguments;
821 : }
822 :
823 :
824 : /** \brief Return the current list of arguments.
825 : *
826 : * This function returns a constant reference to the list of arguments
827 : * currently available in this process.
828 : *
829 : * The list is grown by calling the add_argument() function. It can be
830 : * edited by calling the non-constant get_argument() and keeping a
831 : * reference to the list.
832 : *
833 : * If you asked for some arguments to be expanded, then they will be
834 : * in the expanded state (you will have lost the original pattern).
835 : *
836 : * \return The list of arguments attached to this process.
837 : *
838 : * \sa add_argument()
839 : */
840 0 : process::argument_list_t const & process::get_arguments() const
841 : {
842 0 : return f_arguments;
843 : }
844 :
845 :
846 : /** \brief Add an environment to the command line.
847 : *
848 : * This function adds a new environment variable for the child process to
849 : * use. In most cases this function doesn't get used.
850 : *
851 : * By default all the parent process (this current process) environment
852 : * variables are passed down to the child process. To avoid this behavior,
853 : * call the set_forced_environment() function before the run() function.
854 : *
855 : * An environment variable is defined as a name and a value as in:
856 : *
857 : * \code
858 : * add_environ("HOME", "/home/cppprocess");
859 : * \endcode
860 : *
861 : * If the value is set to the empty string, then the environment variable
862 : * is removed from the list.
863 : *
864 : * \param[in] name The name of the environment variable to add.
865 : * \param[in] value The new value of that environment variable.
866 : *
867 : * \sa get_environ()
868 : */
869 0 : void process::add_environ(std::string const & name, std::string const & value)
870 : {
871 0 : if(value.empty())
872 : {
873 0 : auto it(f_environment.find(name));
874 0 : if(it != f_environment.end())
875 : {
876 0 : f_environment.erase(it);
877 : }
878 : }
879 : else
880 : {
881 0 : f_environment[name] = value;
882 : }
883 0 : }
884 :
885 :
886 : /** \brief Get a reference to the current environment.
887 : *
888 : * This parameter is generally empty since the run() function will use the
889 : * calling process environment variables.
890 : *
891 : * It is possible, however, to hide the calling process environment and
892 : * use these variables instead. This is very good for all sorts of safety
893 : * reasons (i.e. not leak a secret key saved in a variable, for example).
894 : *
895 : * \return A constant reference to the map of environment parameters.
896 : *
897 : * \sa add_environ()
898 : */
899 4 : process::environment_map_t const & process::get_environ() const
900 : {
901 4 : return f_environment;
902 : }
903 :
904 :
905 : /** \brief Set the input filename.
906 : *
907 : * Instead of a pipe or capturing the input, you can also specify
908 : * a filename. This is similar to using the `< filename` syntax on
909 : * a shell command line.
910 : *
911 : * \param[in] filename The name of the input file.
912 : */
913 1 : void process::set_input_filename(std::string const & filename)
914 : {
915 1 : f_input_filename = filename;
916 1 : }
917 :
918 :
919 : /** \brief Retrieve the input filename.
920 : *
921 : * This function returns a copy of the input filename. This is used
922 : * when you don't define an input pipe.
923 : *
924 : * \return The input filename.
925 : */
926 0 : std::string const & process::get_input_filename() const
927 : {
928 0 : return f_input_filename;
929 : }
930 :
931 :
932 : /** \brief The input to be sent to stdin.
933 : *
934 : * Add the input data to be written to the stdin pipe. Note that the input
935 : * cannot be modified once the run() command was called unless the mode
936 : * is PROCESS_MODE_INOUT_INTERACTIVE.
937 : *
938 : * Note that in all case, calling this function multiple times adds more
939 : * data to the input. It does not erase what was added before. The thread
940 : * may eat some of the input in which case it gets removed from the internal
941 : * variable.
942 : *
943 : * \note
944 : * The function is safe and adding new input from the output thread
945 : * (which happens in interactive mode) is protected.
946 : *
947 : * \param[in] input The input of the process (stdin).
948 : *
949 : * \sa add_input(buffer_t const & input)
950 : */
951 3 : void process::add_input(std::string const & input)
952 : {
953 : // this is additive!
954 : //
955 3 : add_input(buffer_t(input.begin(), input.end()));
956 3 : }
957 :
958 :
959 : /** \brief Binary data to be sent to stdin.
960 : *
961 : * When the input data is binary, use the QByteArray instead of a std::string
962 : * so you are sure it gets properly added.
963 : *
964 : * Calling this function multiple times appends the new data to the
965 : * existing data.
966 : *
967 : * Please, see the other set_input() function for additional information.
968 : *
969 : * \note
970 : * When sending a std::string, remember that these are converted to UTF-8
971 : * which is not compatible with purely binary data (i.e. UTF-8, for example,
972 : * does not allow for 0xFE and 0xFF.)
973 : *
974 : * \param[in] input The input of the process (stdin).
975 : *
976 : * \sa add_input(std::string const & input)
977 : */
978 3 : void process::add_input(buffer_t const & input)
979 : {
980 : // this is additive!
981 : //
982 3 : f_input.insert(f_input.end(), input.begin(), input.end());
983 3 : }
984 :
985 :
986 : /** \brief Retrieve a copy of the input buffer as a string.
987 : *
988 : * This function returns the contents of the input buffer as a string.
989 : *
990 : * \return A copy of the input.
991 : *
992 : * \sa get_binary_input()
993 : */
994 6 : std::string process::get_input(bool reset) const
995 : {
996 6 : std::string input(reinterpret_cast<char const *>(f_input.data()), f_input.size());
997 6 : if(reset)
998 : {
999 0 : const_cast<process *>(this)->f_input.clear();
1000 : }
1001 6 : return input;
1002 : }
1003 :
1004 :
1005 : /** \brief Retrieve a copy of the input buffer.
1006 : *
1007 : * This function returns the contents of the input buffer. In most cases,
1008 : * you'll never need this function (you should know what you add to your
1009 : * command input).
1010 : *
1011 : * \return A copy of the input.
1012 : *
1013 : * \sa get_input()
1014 : */
1015 6 : buffer_t process::get_binary_input(bool reset) const
1016 : {
1017 6 : buffer_t const input(f_input);
1018 6 : if(reset)
1019 : {
1020 0 : const_cast<process *>(this)->f_input.clear();
1021 : }
1022 6 : return input;
1023 : }
1024 :
1025 :
1026 : /** \brief Setup a pipe to send the child input to.
1027 : *
1028 : * This function is used to setup a pipe to replace stdin of the process.
1029 : * You are expected to send data to that pipe and the child is expected
1030 : * to read from this pipe and process the data as expected.
1031 : *
1032 : * \warning
1033 : * Only the very first process in a list of processes can be assigned
1034 : * an input pipe. If other processes are given an input pipe, then
1035 : * the start() function will throw an error.
1036 : *
1037 : * \param[in] pipe The pipe used to send data to the child process.
1038 : *
1039 : * \sa get_input_pipe()
1040 : */
1041 0 : void process::set_input_pipe(ed::pipe_connection::pointer_t pipe)
1042 : {
1043 0 : if(pipe->type() != ed::pipe_t::PIPE_CHILD_INPUT)
1044 : {
1045 0 : throw cppprocess_incorrect_pipe_type("incorrect pipe type, expected a PIPE_CHILD_INPUT type of pipe for the input.");
1046 : }
1047 :
1048 0 : f_input_pipe = pipe;
1049 0 : }
1050 :
1051 :
1052 : /** \brief Retrieve the child input pipe.
1053 : *
1054 : * This function returns a pointer to the input pipe. This pipe can be used
1055 : * to send data to the child process while it runs. It will send the data
1056 : * to the child's stdin stream.
1057 : *
1058 : * This pipe works with the eventdispatcher communicator so it is non-blocking
1059 : * and you can add data as space becomes available in the pipe without getting
1060 : * stuck doing so. This means you can also handle the output and error pipes
1061 : * as they get filled up.
1062 : *
1063 : * \return A pointer to the pipe connection used for the process input.
1064 : *
1065 : * \sa set_input_pipe()
1066 : */
1067 6 : ed::pipe_connection::pointer_t process::get_input_pipe() const
1068 : {
1069 6 : return f_input_pipe;
1070 : }
1071 :
1072 :
1073 : /** \brief Set the output filename.
1074 : *
1075 : * Instead of a pipe or capturing the output, you can also specify
1076 : * a filename. This is similar to using the `> filename` syntax on
1077 : * a shell command line.
1078 : *
1079 : * \param[in] filename The name of the output file.
1080 : */
1081 1 : void process::set_output_filename(std::string const & filename)
1082 : {
1083 1 : f_output_filename = filename;
1084 1 : }
1085 :
1086 :
1087 : /** \brief Retrieve the output filename.
1088 : *
1089 : * This function returns a copy of the output filename. This is used
1090 : * when you don't define an output pipe.
1091 : *
1092 : * \return The output filename.
1093 : */
1094 0 : std::string const & process::get_output_filename() const
1095 : {
1096 0 : return f_output_filename;
1097 : }
1098 :
1099 :
1100 : /** \brief Setup capture of output.
1101 : *
1102 : * By default, the output is set to stdout or an output pipe. You can also
1103 : * request that the process class capture the output to a buffer by calling
1104 : * this function with true.
1105 : *
1106 : * If you setup an output pipe, this flag is ignored.
1107 : *
1108 : * \param[in] capture Whether to capture the output (true) or not (false).
1109 : */
1110 3 : void process::set_capture_output(bool capture)
1111 : {
1112 3 : f_capture_output = capture;
1113 3 : }
1114 :
1115 :
1116 : /** \brief Check whether the output will be captured or not.
1117 : *
1118 : * This function returns the capture flag.
1119 : *
1120 : * When the capture flag is true, the process output will be captured in an
1121 : * internal buffer.
1122 : *
1123 : * \return true if the output is to be captured by the process object.
1124 : */
1125 5 : bool process::get_capture_output() const
1126 : {
1127 5 : return f_capture_output;
1128 : }
1129 :
1130 :
1131 : /** \brief Set output capture done callback.
1132 : *
1133 : * This function lets you define a callback which gets called whenever the
1134 : * whole output is received.
1135 : *
1136 : * \warning
1137 : * You cannot use this function when you use your own output pipe.
1138 : *
1139 : * \param[in] callback The callback to call when SIGCHLD is received.
1140 : */
1141 0 : void process::set_output_capture_done(capture_done_t callback)
1142 : {
1143 0 : f_output_done_callback = callback;
1144 0 : }
1145 :
1146 :
1147 : /** \brief Read the output of the command.
1148 : *
1149 : * This function reads the output of the process. This function converts
1150 : * the output to UTF-8. Note that if some bytes are missing this function
1151 : * is likely to fail. If you are reading the data little by little as it
1152 : * comes in, you may want to use the get_binary_output() function
1153 : * instead. That way you can detect characters such as the "\n" and at
1154 : * that point convert the data from the previous "\n" you found in the
1155 : * buffer to that new "\n". This will generate valid UTF-8 strings.
1156 : *
1157 : * This function is most often used by users of commands that process
1158 : * one given input and generate one given output all at once.
1159 : *
1160 : * \param[in] reset Whether the output so far should be cleared.
1161 : *
1162 : * \return The current output buffer.
1163 : *
1164 : * \sa get_binary_output()
1165 : */
1166 9 : std::string process::get_output(bool reset) const
1167 : {
1168 9 : std::string const output(reinterpret_cast<char const *>(f_output.data()), f_output.size());
1169 9 : if(reset)
1170 : {
1171 0 : const_cast<process *>(this)->f_output.clear();
1172 : }
1173 9 : return output;
1174 : }
1175 :
1176 :
1177 : /** \brief Get the trimmed output.
1178 : *
1179 : * The get_output() function returns the output as is, with all the
1180 : * characters. Quite often, though, you do not want the ending `'\n'`,
1181 : * introductory spaces or tabs, or even multiple spaces when aligned
1182 : * column output is used by the process.
1183 : *
1184 : * This function can be used to trimmed all of that junk for you. It
1185 : * will always remove the starting and ending spaces and new line,
1186 : * carriage return characters.
1187 : *
1188 : * When \p inside is true, it also replaces multiple spaces within
1189 : * the string in a single space. This feature also replaces all spaces
1190 : * with 0x20 (`' '`).
1191 : *
1192 : * \param[in] inside Whether to remove double, triple, etc. spaces inside
1193 : * the string.
1194 : * \param[in] reset Whether to reset the value after this call.
1195 : *
1196 : * \return The trimmed output string.
1197 : *
1198 : * \sa snap::trim_string() (in snapdev)
1199 : */
1200 2 : std::string process::get_trimmed_output(bool inside, bool reset) const
1201 : {
1202 2 : return snap::trim_string(get_output(reset), true, true, inside);
1203 : }
1204 :
1205 :
1206 : /** \brief Read the output of the command as a binary buffer.
1207 : *
1208 : * This function reads the output of the process in binary (untouched).
1209 : *
1210 : * This function does not fail like the get_output() which attempts to
1211 : * convert the output of the function to UTF-8. Also the output of the
1212 : * command may not be UTF-8 in which case you would have to use the
1213 : * binary version and use a different conversion.
1214 : *
1215 : * \param[in] reset Whether the output so far should be cleared.
1216 : *
1217 : * \return The current output buffer.
1218 : *
1219 : * \sa get_output()
1220 : */
1221 5 : buffer_t process::get_binary_output(bool reset) const
1222 : {
1223 5 : buffer_t const output(f_output);
1224 5 : if(reset)
1225 : {
1226 0 : const_cast<process *>(this)->f_output.clear();
1227 : }
1228 5 : return output;
1229 : }
1230 :
1231 :
1232 : /** \brief Setup a pipe where the process output is to be written.
1233 : *
1234 : * This function is used to setup a pipe which will receive data from
1235 : * the stdout of the command being started by the process object.
1236 : *
1237 : * The pipe is going to be setup as non-blocking, which means you can
1238 : * attempt a very large read (pipes on Linux are generally supporting
1239 : * about 64Kb of data) and your process won't be blocked if the amount
1240 : * of data is smaller that what you requested.
1241 : *
1242 : * \warning
1243 : * Only the very last process or a list of piped processes can be
1244 : * assigned an output pipe.
1245 : *
1246 : * \param[in] pipe The pipe to attach to this process output.
1247 : *
1248 : * \sa get_output_pipe()
1249 : */
1250 0 : void process::set_output_pipe(ed::pipe_connection::pointer_t pipe)
1251 : {
1252 0 : if(pipe->type() != ed::pipe_t::PIPE_CHILD_OUTPUT)
1253 : {
1254 0 : throw cppprocess_incorrect_pipe_type("incorrect pipe type, expected a PIPE_CHILD_OUTPUT type of pipe for the output.");
1255 : }
1256 :
1257 0 : f_output_pipe = pipe;
1258 0 : }
1259 :
1260 :
1261 : /** \brief Retrieve the pointer to the output pipe.
1262 : *
1263 : * This function retrieves the pointer of the current output pipe.
1264 : * By default, this is a null pointer.
1265 : *
1266 : * \return The callback interface pointer.
1267 : *
1268 : * \sa set_output_pipe()
1269 : */
1270 3 : ed::pipe_connection::pointer_t process::get_output_pipe() const
1271 : {
1272 3 : return f_output_pipe;
1273 : }
1274 :
1275 :
1276 : /** \brief Pipe the output of this process to the next process.
1277 : *
1278 : * This function is used to pipe processes one after the other.
1279 : *
1280 : * The next process receives as input the output of this process,
1281 : * in effect creating a pipeline of Unix processes.
1282 : *
1283 : * The function is called "add" (next process) because you can
1284 : * pipe the output of one process to any number of processes'
1285 : * input pipe. This is done by one of our internal pipe object
1286 : * which is capable of such a feat.
1287 : *
1288 : * \note
1289 : * The pipes created in this case are created internally and you
1290 : * have no direct or indirect access to them except from within
1291 : * the processes added here.
1292 : *
1293 : * \param[in] next A process that will receive the output of this
1294 : * process as input.
1295 : */
1296 2 : void process::add_next_process(pointer_t next)
1297 : {
1298 2 : f_next.push_back(next);
1299 2 : }
1300 :
1301 :
1302 : /** \brief Clear the list of next processes.
1303 : *
1304 : * This function clears the list of all the next processes defined
1305 : * in this process, cutting off the pipeline.
1306 : */
1307 0 : void process::clear_next_process()
1308 : {
1309 0 : f_next.clear();
1310 0 : }
1311 :
1312 :
1313 : /** \brief Retrieve the list of next processes.
1314 : *
1315 : * This function returns the list of next processes as created by the
1316 : * add_next_process() function.
1317 : *
1318 : * A next process receives as input the output of this process--i.e.
1319 : * if creates a pair of piped processes. Any number of processes
1320 : * can be piped in this manner.
1321 : *
1322 : * When the list is empty, the output is instead sent to the output
1323 : * pipe connection or, if not such pipe is defined, to the output
1324 : * buffer which you can retrieve later.
1325 : *
1326 : * If there is more than one next process, then the process creates
1327 : * a process_tee class which is used to send the output of this
1328 : * process to all the following processes.
1329 : *
1330 : * \return The list of processes to run after this one.
1331 : */
1332 3 : process::list_t process::get_next_processes() const
1333 : {
1334 3 : return f_next;
1335 : }
1336 :
1337 :
1338 : /** \brief Set the error filename.
1339 : *
1340 : * Instead of a pipe or capturing the error, you can also specify
1341 : * a filename. This is similar to using the `2> filename` syntax on
1342 : * a shell command line.
1343 : *
1344 : * \param[in] filename The name of the error file.
1345 : */
1346 0 : void process::set_error_filename(std::string const & filename)
1347 : {
1348 0 : f_error_filename = filename;
1349 0 : }
1350 :
1351 :
1352 : /** \brief Retrieve the error filename.
1353 : *
1354 : * This function returns a copy of the error filename. This is used
1355 : * when you don't define an error pipe.
1356 : *
1357 : * \return The error filename.
1358 : */
1359 0 : std::string const & process::get_error_filename() const
1360 : {
1361 0 : return f_error_filename;
1362 : }
1363 :
1364 :
1365 : /** \brief Setup capture of the error stream.
1366 : *
1367 : * By default, the error stream is set to stderr. You can also request that
1368 : * the process object captures the error stream to a buffer by calling
1369 : * this function with true.
1370 : *
1371 : * If you setup an error pipe, this flag is ignored.
1372 : *
1373 : * \param[in] capture Whether to capture the error stream (true) or not (false).
1374 : */
1375 1 : void process::set_capture_error(bool capture)
1376 : {
1377 1 : f_capture_error = capture;
1378 1 : }
1379 :
1380 :
1381 : /** \brief Check whether the error stream will be captured or not.
1382 : *
1383 : * This function returns the capture flag for the error stream.
1384 : *
1385 : * When the capture flag is true, the process error stream will be captured
1386 : * in an internal buffer.
1387 : *
1388 : * \return true if the error stream is to be captured by the process object.
1389 : */
1390 2 : bool process::get_capture_error() const
1391 : {
1392 2 : return f_capture_error;
1393 : }
1394 :
1395 :
1396 : /** \brief Read the error output of the command.
1397 : *
1398 : * This function reads the error output stream of the process. This
1399 : * function converts the output to UTF-8. Note that if some bytes are
1400 : * missing this function is likely to fail. If you are reading the
1401 : * data little by little as it comes in, you may want to use the
1402 : * get_binary_output() function instead. That way you can detect
1403 : * characters such as the "\n" and at that point convert the data
1404 : * from the previous "\n" you found in the buffer to that new "\n".
1405 : * This will generate valid UTF-8 strings.
1406 : *
1407 : * This function is most often used when stderr is to be saved
1408 : * in a different file than the default.
1409 : *
1410 : * \todo
1411 : * Look at validating the UTF-8 data.
1412 : *
1413 : * \param[in] reset Whether the error output so far should be cleared.
1414 : *
1415 : * \return The current error output buffer.
1416 : *
1417 : * \sa get_binary_error()
1418 : */
1419 6 : std::string process::get_error(bool reset) const
1420 : {
1421 6 : std::string const error(reinterpret_cast<char const *>(f_error.data()), f_error.size());
1422 6 : if(reset)
1423 : {
1424 0 : const_cast<process *>(this)->f_error.clear();
1425 : }
1426 6 : return error;
1427 : }
1428 :
1429 :
1430 : /** \brief Read the error output of the command as a binary buffer.
1431 : *
1432 : * This function reads the error output of the process in binary (untouched).
1433 : *
1434 : * This function does not fail like get_error() which attempts to
1435 : * convert the output of the function to UTF-8. Also the error output
1436 : * of the command may not be UTF-8 in which case you would have to use
1437 : * the binary version and use a different conversion.
1438 : *
1439 : * \param[in] reset Whether the error output so far should be cleared.
1440 : *
1441 : * \return The current error output buffer.
1442 : *
1443 : * \sa get_error()
1444 : */
1445 5 : buffer_t process::get_binary_error(bool reset) const
1446 : {
1447 5 : buffer_t const error(f_error);
1448 5 : if(reset)
1449 : {
1450 0 : const_cast<process *>(this)->f_error.clear();
1451 : }
1452 5 : return error;
1453 : }
1454 :
1455 :
1456 : /** \brief Setup a pipe where the process errors are to be written.
1457 : *
1458 : * This function is used to setup a pipe which will receive data from
1459 : * the stderr of the command being started by the process object.
1460 : *
1461 : * The pipe is going to be setup as non-blocking, which means you can
1462 : * attempt a very large read (pipes on Linux are generally supporting
1463 : * about 64Kb of data) and your process won't be blocked if the amount
1464 : * of data is smaller than what you requested.
1465 : *
1466 : * \param[in] callback The callback class that is called on output arrival.
1467 : *
1468 : * \sa get_error_pipe()
1469 : */
1470 0 : void process::set_error_pipe(ed::pipe_connection::pointer_t pipe)
1471 : {
1472 0 : if(pipe->type() != ed::pipe_t::PIPE_CHILD_OUTPUT)
1473 : {
1474 0 : throw cppprocess_incorrect_pipe_type("incorrect pipe type, expected a PIPE_CHILD_OUTPUT type of pipe for the error.");
1475 : }
1476 :
1477 0 : f_error_pipe = pipe;
1478 0 : }
1479 :
1480 :
1481 : /** \brief Retrieve the pointer to the error pipe.
1482 : *
1483 : * This function retrieves the pointer of the current error pipe.
1484 : * By default, this is a null pointer.
1485 : *
1486 : * \return The callback interface pointer.
1487 : *
1488 : * \sa set_error_pipe()
1489 : */
1490 5 : ed::pipe_connection::pointer_t process::get_error_pipe() const
1491 : {
1492 5 : return f_error_pipe;
1493 : }
1494 :
1495 :
1496 : /** \brief Start the process.
1497 : *
1498 : * This function creates all the necessary things that the process requires
1499 : * and start the command.
1500 : *
1501 : * If the function encounters problems before it can run the child process,
1502 : * it returns -1 instead.
1503 : *
1504 : * The function always uses `fork()` and `execvpe()`. That way we handle
1505 : * one single case, which is much easier to maintain. The process is started
1506 : * in the background. This function doesn't wait for the process to be done.
1507 : *
1508 : * The input can be a buffer where you add data using add_input(). It can
1509 : * also be setup with your own pipe_connection object. If neither is
1510 : * specified, the process is given your stdin as a default.
1511 : *
1512 : * The output can automatically be captured or you can setup your own
1513 : * pipe_connection object to receive the output. If neither is specified,
1514 : * the process is given your stdout as a default.
1515 : *
1516 : * Like the output, the error stream can be captured or sent to your own
1517 : * pipe. It otherwise defaults to stderr.
1518 : *
1519 : * If you are not using ed::communicator (or at least you did not call the
1520 : * ed::communicator::run() function), you can wait on the process with
1521 : * the wait() function. This function will call the ed::communicator::run()
1522 : * loop. If you supplied your own pipes, you'll want to make sure to close
1523 : * them and remove them from the ed::communicator once done with them
1524 : * otherwise the wait() function will be stuck forever. The SIGCHLD signal
1525 : * is also automatically handled by the wait() function.
1526 : *
1527 : * \return 0 on success or -1 if an error occurs.
1528 : *
1529 : * \sa wait()
1530 : * \sa add_input()
1531 : * \sa set_input_pipe()
1532 : * \sa set_capture_output()
1533 : * \sa get_output()
1534 : * \sa set_capture_error()
1535 : * \sa get_error()
1536 : */
1537 6 : int process::start()
1538 : {
1539 12 : if(start_process(
1540 12 : ed::pipe_connection::pointer_t()
1541 : , 0
1542 18 : , ed::pipe_connection::pointer_t()) != 0)
1543 : {
1544 0 : return -1;
1545 : }
1546 :
1547 6 : if(!f_next.empty())
1548 : {
1549 2 : if(f_next.size() != f_prepared_output.size())
1550 : {
1551 : // the prepare_output() should have generated an error already
1552 : // so we should never get here, hence the logic error
1553 : //
1554 : throw cppprocess_logic_error(
1555 : "incorrect number of output pipes (expected "
1556 0 : + std::to_string(f_next.size())
1557 0 : + ", found "
1558 0 : + std::to_string(f_prepared_output.size())
1559 0 : + ")");
1560 : }
1561 :
1562 2 : int idx(0);
1563 4 : for(auto & n : f_next)
1564 : {
1565 8 : if(n->start_process(
1566 : f_intermediate_output_pipe
1567 : , idx
1568 6 : , f_internal_input_pipe) != 0)
1569 : {
1570 0 : return -1;
1571 : }
1572 2 : ++idx;
1573 : }
1574 : }
1575 :
1576 6 : if(f_intermediate_output_pipe != nullptr)
1577 : {
1578 4 : f_intermediate_output_pipe->forked();
1579 : }
1580 :
1581 6 : if(f_next.size() == 1)
1582 : {
1583 4 : pointer_t n(*f_next.begin());
1584 2 : while(n->f_next.size() == 1)
1585 : {
1586 0 : n = *n->f_next.begin();
1587 : }
1588 :
1589 2 : if(n->f_next.empty())
1590 : {
1591 : // we found the last item and no tee_pipe
1592 : //
1593 2 : if(n->f_intermediate_output_pipe != nullptr)
1594 : {
1595 1 : n->f_intermediate_output_pipe->forked();
1596 : }
1597 : }
1598 : }
1599 :
1600 6 : return 0;
1601 : }
1602 :
1603 :
1604 : /** \brief Wait for the command to be done.
1605 : *
1606 : * If you are using the ed::communicator and start a command, you will
1607 : * receive an event whenever the command is done. However, if you are
1608 : * not using ed::comminocator, this function helps you in hiding the
1609 : * grueling details on how to handle the event loop just to wait for
1610 : * a command to run.
1611 : *
1612 : * \exception cppprocess_recursive_call
1613 : * However, if you use ed::communicator and are already in the run()
1614 : * function, you can't call this function. It will raise this exception
1615 : * if you tried to do so. Of course, it is assumed that you also called
1616 : * the start() function to actually start the process.
1617 : *
1618 : * \exception cppprocess_not_started
1619 : * If one of the processes was not started (this process or one of its
1620 : * next processes) then this exception is raised.
1621 : *
1622 : * \return The exit code from the command.
1623 : */
1624 6 : int process::wait()
1625 : {
1626 6 : if(f_communicator->is_running())
1627 : {
1628 0 : throw cppprocess_recursive_call("you already are in the communicator::run() function, you cannot call process::wait().");
1629 : }
1630 :
1631 6 : if(f_child == -1
1632 6 : || !f_running)
1633 : {
1634 0 : throw cppprocess_not_started("the process was not started or already died.");
1635 : }
1636 :
1637 12 : list_t n(f_next);
1638 8 : for(auto & it : n)
1639 : {
1640 4 : if(it->f_child == -1
1641 2 : || !it->f_running)
1642 : {
1643 0 : throw cppprocess_not_started("one of the next processes was not started or already died.");
1644 : }
1645 :
1646 2 : n.insert(n.end(), it->f_next.begin(), it->f_next.end());
1647 : }
1648 :
1649 12 : ed::signal_child::pointer_t child_signal(ed::signal_child::get_instance());
1650 :
1651 : // this object may not have a shared pointer so we can't add it to the
1652 : // `n` list; for this reason we have to have a special case, unfortunately
1653 : //
1654 12 : child_signal->add_listener(
1655 : f_child
1656 12 : , std::bind(&process::child_done, this, std::placeholders::_1));
1657 :
1658 8 : for(auto & it : n)
1659 : {
1660 6 : child_signal->add_listener(
1661 2 : it->f_child
1662 4 : , std::bind(&process::child_done, it.get(), std::placeholders::_1));
1663 : }
1664 :
1665 6 : f_communicator->run();
1666 :
1667 12 : return f_exit_code;
1668 : }
1669 :
1670 :
1671 8 : void process::child_done(ed::child_status status)
1672 : {
1673 : // note that all the child_done() callbacks get called because the
1674 : // communicator does not (currently) have any idea of which one needs
1675 : // to be called so here we make sure we only handle the correct one
1676 : //
1677 : #ifdef _DEBUG
1678 8 : if(status.child_pid() != f_child)
1679 : {
1680 : throw cppprocess_logic_error(
1681 : "child pid mismatch in process::child_done(),"
1682 : " please check that you used the correct PID when binding"
1683 0 : " this function.");
1684 : }
1685 : #endif
1686 :
1687 8 : f_exit_code = status.exit_code();
1688 :
1689 8 : if(f_process_done != nullptr)
1690 : {
1691 0 : f_process_done(status);
1692 : }
1693 8 : }
1694 :
1695 :
1696 8 : int process::start_process(
1697 : ed::pipe_connection::pointer_t output_fifo
1698 : , int output_index
1699 : , ed::pipe_connection::pointer_t input_fifo)
1700 : {
1701 8 : if(f_running)
1702 : {
1703 : // already running
1704 0 : return -1;
1705 : }
1706 :
1707 : // prepare the pipes
1708 : //
1709 8 : prepare_input(output_fifo);
1710 8 : prepare_output();
1711 8 : prepare_error();
1712 :
1713 8 : f_child = fork();
1714 8 : switch(f_child)
1715 : {
1716 0 : case -1:
1717 : // an error occurred
1718 : //
1719 0 : return -1;
1720 :
1721 0 : case 0:
1722 : // child
1723 : //
1724 : // we want to run the execvpe() command
1725 : //
1726 0 : execute_command(output_fifo, output_index, input_fifo);
1727 :
1728 : // the child can't safely return so just exit now
1729 : //
1730 0 : exit(1);
1731 : snap::NOT_REACHED();
1732 : return -1;
1733 :
1734 8 : default:
1735 : // parent
1736 : //
1737 8 : if(f_input_pipe != nullptr)
1738 : {
1739 0 : f_input_pipe->forked();
1740 : }
1741 8 : if(f_internal_input_pipe != nullptr)
1742 : {
1743 3 : f_internal_input_pipe->forked();
1744 : }
1745 8 : if(f_output_pipe != nullptr)
1746 : {
1747 0 : f_output_pipe->forked();
1748 : }
1749 :
1750 : // this one is done outside, here it's too soon in the case of a pipeline
1751 : // since we need both sides to create the next process
1752 : //
1753 : // if(f_intermediate_output_pipe != nullptr)
1754 : // {
1755 : //std::cerr << "--- intermediate output pipe forked()\n";
1756 : // f_intermediate_output_pipe->forked();
1757 : // }
1758 : //
1759 8 : if(f_error_pipe != nullptr)
1760 : {
1761 0 : f_error_pipe->forked();
1762 : }
1763 8 : if(f_internal_error_pipe != nullptr)
1764 : {
1765 1 : f_internal_error_pipe->forked();
1766 : }
1767 :
1768 8 : f_running = true;
1769 :
1770 8 : return 0;
1771 :
1772 : }
1773 : snap::NOT_REACHED();
1774 : }
1775 :
1776 :
1777 0 : void process::execute_command(
1778 : ed::pipe_connection::pointer_t output_fifo
1779 : , int output_index
1780 : , ed::pipe_connection::pointer_t input_fifo)
1781 : {
1782 : // child
1783 : //
1784 : try
1785 : {
1786 : // convert arguments so we can use them with execvpe()
1787 : //
1788 0 : std::vector<char const *> args_strings;
1789 0 : args_strings.reserve(1 + f_arguments.size() + 1);
1790 0 : args_strings.push_back(f_command.c_str());
1791 0 : for(auto const & a : f_arguments)
1792 : {
1793 0 : args_strings.push_back(a.c_str());
1794 : }
1795 0 : args_strings.push_back(nullptr); // NULL terminated
1796 :
1797 : // convert the environment variables so we can use them with execvpe()
1798 : //
1799 0 : environment_map_t src_envs(f_environment);
1800 0 : if(!f_forced_environment)
1801 : {
1802 : // since we do not limit the child to only the specified
1803 : // environment, add ours but do not overwrite anything
1804 : //
1805 0 : for(char ** env(environ); *env != nullptr; ++env)
1806 : {
1807 0 : char const * s(*env);
1808 0 : char const * n(s);
1809 0 : while(*s != '\0')
1810 : {
1811 0 : if(*s == '=')
1812 : {
1813 0 : std::string const name(n, s - n);
1814 :
1815 : // do not overwrite user overridden values
1816 : //
1817 0 : if(src_envs.find(name) == src_envs.end())
1818 : {
1819 : // in Linux all is UTF-8 so we are already good here
1820 : //
1821 0 : src_envs[name] = s + 1;
1822 : }
1823 0 : break;
1824 : }
1825 0 : ++s;
1826 : }
1827 : }
1828 : }
1829 0 : std::vector<char const *> envs_strings;
1830 0 : for(auto const & it : src_envs)
1831 : {
1832 0 : envs_strings.push_back(strdup((it.first + "=" + it.second).c_str()));
1833 : }
1834 0 : envs_strings.push_back(nullptr); // NULL terminated
1835 :
1836 : // replace the stdin and stdout (and optionally stderr)
1837 : // with their respective pipes
1838 : //
1839 0 : if(f_prepared_input != -1)
1840 : {
1841 0 : if(dup2(f_prepared_input, STDIN_FILENO) < 0) // stdin
1842 : {
1843 0 : throw cppprocess_initialization_failed("dup2() of the stdin pipe failed");
1844 : }
1845 : }
1846 0 : if(f_prepared_output[output_index] != -1)
1847 : {
1848 0 : if(dup2(f_prepared_output[output_index], STDOUT_FILENO) < 0) // stdout
1849 : {
1850 0 : if(f_prepared_input != -1)
1851 : {
1852 0 : close(f_prepared_input);
1853 : }
1854 0 : throw cppprocess_initialization_failed("dup2() of the stdout pipe failed");
1855 : }
1856 : }
1857 0 : if(f_prepared_error != -1)
1858 : {
1859 0 : if(dup2(f_prepared_error, STDERR_FILENO) < 0) // stderr
1860 : {
1861 0 : if(f_prepared_input != -1)
1862 : {
1863 0 : close(f_prepared_input);
1864 : }
1865 0 : if(f_prepared_output[output_index] != -1)
1866 : {
1867 0 : close(f_prepared_output[output_index]);
1868 : }
1869 0 : throw cppprocess_initialization_failed("dup2() of the stderr pipe failed");
1870 : }
1871 : }
1872 :
1873 : // we duplicated the files we were interested in as required,
1874 : // now close all the other pipes
1875 : //
1876 0 : if(input_fifo != nullptr)
1877 : {
1878 0 : input_fifo->close();
1879 : }
1880 0 : if(f_input_pipe != nullptr)
1881 : {
1882 0 : f_input_pipe->close();
1883 : }
1884 0 : if(f_internal_input_pipe != nullptr)
1885 : {
1886 0 : f_internal_input_pipe->close();
1887 : }
1888 0 : if(f_output_pipe != nullptr)
1889 : {
1890 0 : f_output_pipe->close();
1891 : }
1892 0 : if(output_fifo != nullptr)
1893 : {
1894 0 : output_fifo->close();
1895 : }
1896 0 : if(f_intermediate_output_pipe != nullptr)
1897 : {
1898 0 : f_intermediate_output_pipe->close();
1899 : }
1900 0 : if(f_error_pipe != nullptr)
1901 : {
1902 0 : f_error_pipe->close();
1903 : }
1904 0 : if(f_internal_error_pipe != nullptr)
1905 : {
1906 0 : f_internal_error_pipe->close();
1907 : }
1908 :
1909 0 : execvpe(
1910 : f_command.c_str(),
1911 0 : const_cast<char * const *>(&args_strings[0]),
1912 0 : const_cast<char * const *>(&envs_strings[0])
1913 : );
1914 :
1915 : // the child returns only if execvp() fails, which is possible
1916 : //
1917 0 : int const e(errno);
1918 0 : SNAP_LOG_FATAL
1919 0 : << "Starting child process \""
1920 : << f_command
1921 : << " "
1922 0 : << snap::join_strings(f_arguments, " ")
1923 0 : << "\" failed. (errno: "
1924 : << e
1925 : << " -- "
1926 0 : << strerror(e)
1927 : << ")"
1928 : << SNAP_LOG_SEND;
1929 : }
1930 0 : catch(libexcept::exception_t const & e)
1931 : {
1932 0 : SNAP_LOG_FATAL
1933 0 : << "process::run(): snap_exception caught: "
1934 0 : << e.what()
1935 : << SNAP_LOG_SEND;
1936 : }
1937 0 : catch(std::exception const & e)
1938 : {
1939 : // the snap_logic_exception is not a snap_exception
1940 : // and other libraries may generate other exceptions
1941 : // (i.e. libtld, libQtCassandra...)
1942 : //
1943 0 : SNAP_LOG_FATAL
1944 0 : << "process::run(): std::exception caught: "
1945 0 : << e.what()
1946 : << SNAP_LOG_SEND;
1947 : }
1948 0 : catch(...)
1949 : {
1950 0 : SNAP_LOG_FATAL
1951 0 : << "process::run(): unknown exception caught!"
1952 : << SNAP_LOG_SEND;
1953 : }
1954 0 : }
1955 :
1956 :
1957 : /** \brief Setup the input pipe.
1958 : *
1959 : * This function prepare the input pipe. If this process is a \em next
1960 : * process, then the output_fifo will be set to the output of the previous
1961 : * process. In effect, this allows us to pipe any number of commands
1962 : * automatically and with just one pipe object.
1963 : *
1964 : * The output_fifo is that pipe file descriptor.
1965 : *
1966 : * The last process should instead setup an output fifo with the
1967 : * set_output_pipe() function.
1968 : *
1969 : * \note
1970 : * If an output fifo gets set in a process other than a last process
1971 : * (i.e. a process with at least one next() process), then the function
1972 : * throws an error (i.t. invalid setup).
1973 : */
1974 8 : void process::prepare_input(ed::pipe_connection::pointer_t output_fifo)
1975 : {
1976 : // piping between process objects
1977 : //
1978 8 : if(output_fifo != nullptr)
1979 : {
1980 : // we are being piped from a previous command, we must be
1981 : // using this output_fifo as our input
1982 : //
1983 2 : if(f_input_pipe != nullptr)
1984 : {
1985 0 : throw cppprocess_invalid_parameters("you cannot pipe a command (add_next()) and define your own input pipe.");
1986 : }
1987 2 : if(!f_input.empty())
1988 : {
1989 0 : throw cppprocess_invalid_parameters("you cannot pipe a command (add_next()) and define your own input data.");
1990 : }
1991 :
1992 : //f_prepared_input = output_fifo->get_other_socket();
1993 2 : f_prepared_input = output_fifo->get_socket();
1994 2 : return;
1995 : }
1996 :
1997 : // user specified pipe
1998 : //
1999 6 : if(f_input_pipe != nullptr)
2000 : {
2001 0 : if(!f_input.empty())
2002 : {
2003 0 : throw cppprocess_invalid_parameters("you cannot define pipe and input data in the same process.");
2004 : }
2005 :
2006 0 : f_prepared_input = f_input_pipe->get_other_socket();
2007 0 : return;
2008 : }
2009 :
2010 6 : if(!f_input_filename.empty())
2011 : {
2012 1 : f_input_file.reset(open(
2013 : f_input_filename.c_str()
2014 : , O_RDONLY));
2015 1 : f_prepared_input = f_input_file.get();
2016 1 : return;
2017 : }
2018 :
2019 5 : if(!f_input.empty())
2020 : {
2021 : // the user supplied a buffer instead of a pipe, we create a pipe
2022 : // to send that buffer which will be pretty much automatic
2023 : //
2024 3 : f_internal_input_pipe = std::make_shared<direct_input_data>(this, f_input);
2025 3 : f_prepared_input = f_internal_input_pipe->get_other_socket();
2026 3 : f_communicator->add_connection(f_internal_input_pipe);
2027 3 : return;
2028 : }
2029 :
2030 : // as a fallback, pass our stdin
2031 : //
2032 2 : f_prepared_input = STDIN_FILENO;
2033 : }
2034 :
2035 :
2036 : /** \brief Prepare the output pipes.
2037 : *
2038 : * The output can be unique (99% of the time) or it can be duplicated
2039 : * with a tee pipe.
2040 : *
2041 : * The tee pipe is an internal feature used when a process is piped to
2042 : * two or more other processes. Each one of the following processes
2043 : * receives a copy of the previous process output.
2044 : *
2045 : * If there are no output processes, then the output is expected to
2046 : * use a pipe that you define with set_output_pipe(). If you don't
2047 : * define an output pipe, then stdout is used.
2048 : */
2049 8 : void process::prepare_output()
2050 : {
2051 : // the output has four cases
2052 : //
2053 : // 1. there is exactly one process following this one
2054 : //
2055 : // we need a simple FIFO between the two processes; this is handled
2056 : // internally
2057 : //
2058 : // in this case it is illegal for the user to define an output FIFO
2059 : //
2060 : // 2. there is more than one process following this one (tee-feature)
2061 : //
2062 : // we create one output FIFO and each of the following processes
2063 : // will receive a specific input FIFO; our output FIFO will
2064 : // duplicate all the data it receives in all the input FIFOs
2065 : //
2066 : // in this case it is illegal for the user to define an output FIFO
2067 : //
2068 : // 3. no following processes & a user defined output FIFO
2069 : //
2070 : // the user output FIFO is used for our stdout
2071 : //
2072 : // 4. no following processes, no user defined output FIFO, capture is true
2073 : //
2074 : // create an internal FIFO and save output in process
2075 : //
2076 : // 5. no following processes & no user defined output FIFO
2077 : //
2078 : // we use the default stdout
2079 : //
2080 :
2081 8 : switch(f_next.size())
2082 : {
2083 6 : case 0:
2084 : // no piping to another process:
2085 : // 1. use the user output if defined (f_output_pipe)
2086 : // 2. use internal output if f_capture_output is true
2087 : // 3. use stdout
2088 : //
2089 6 : if(f_output_pipe != nullptr)
2090 : {
2091 0 : f_prepared_output.push_back(f_output_pipe->get_socket());
2092 : }
2093 6 : else if(!f_output_filename.empty())
2094 : {
2095 1 : f_output_file.reset(open(
2096 : f_output_filename.c_str()
2097 : , O_WRONLY | O_CREAT | O_TRUNC
2098 : , S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IRGRP));
2099 1 : f_prepared_output.push_back(f_output_file.get());
2100 : }
2101 5 : else if(f_capture_output)
2102 : {
2103 3 : f_intermediate_output_pipe = std::make_shared<capture_output_pipe>(this, f_output);
2104 3 : f_prepared_output.push_back(f_intermediate_output_pipe->get_other_socket());
2105 3 : f_communicator->add_connection(f_intermediate_output_pipe);
2106 : }
2107 : else
2108 : {
2109 : // as a fallback, pass our stdout
2110 : //
2111 2 : f_prepared_output.push_back(STDOUT_FILENO);
2112 : }
2113 6 : break;
2114 :
2115 2 : case 1:
2116 : // normal case where there is a one to one match
2117 : // (i.e. not tee-feature required)
2118 : //
2119 2 : if(f_output_pipe != nullptr)
2120 : {
2121 0 : throw cppprocess_invalid_parameters("you cannot pipe a command (add_next()) and define your own output pipe in the sender.");
2122 : }
2123 2 : f_intermediate_output_pipe = std::make_shared<direct_output_to_input_pipe>();
2124 2 : f_prepared_output.push_back(f_intermediate_output_pipe->get_other_socket());
2125 :
2126 : // in this one case, the FIFO works automatically, our communicator
2127 : // does not have to intervene -- so no add required
2128 : //
2129 : //f_communicator->add_connection(f_intermediate_output_pipe);
2130 2 : break;
2131 :
2132 0 : default:
2133 : // special case where we create one output pipe that
2134 : // distribute the output to N input pipes for the next
2135 : // N processes
2136 : //
2137 0 : if(f_output_pipe != nullptr)
2138 : {
2139 0 : throw cppprocess_invalid_parameters("you cannot pipe the output of a command (add_next()) to many other commands and define your own output pipe in the sender.");
2140 : }
2141 0 : f_intermediate_output_pipe = std::make_shared<tee_pipe>(f_next.size());
2142 0 : for(std::size_t idx(0); idx < f_next.size(); ++idx)
2143 : {
2144 0 : f_prepared_output.push_back(std::dynamic_pointer_cast<tee_pipe>(f_intermediate_output_pipe)->get_output_pipe(idx)->get_other_socket());
2145 0 : }
2146 0 : f_communicator->add_connection(f_intermediate_output_pipe);
2147 0 : break;
2148 :
2149 : }
2150 8 : }
2151 :
2152 :
2153 : /** \brief Prepare the error file descriptor.
2154 : *
2155 : * This function prepares the error file descriptor.
2156 : *
2157 : * The error pipe is set to stderr if you did not setup an error pipe with
2158 : * the set_error_pipe() function.
2159 : */
2160 8 : void process::prepare_error()
2161 : {
2162 : // user specified pipe
2163 : //
2164 8 : if(f_error_pipe != nullptr)
2165 : {
2166 0 : f_prepared_error = f_error_pipe->get_other_socket();
2167 0 : return;
2168 : }
2169 :
2170 8 : if(!f_error_filename.empty())
2171 : {
2172 0 : f_error_file.reset(open(
2173 : f_error_filename.c_str()
2174 : , O_WRONLY | O_CREAT | O_TRUNC
2175 : , S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IRGRP));
2176 0 : f_prepared_error = f_error_file.get();
2177 0 : return;
2178 : }
2179 :
2180 8 : if(f_capture_error)
2181 : {
2182 1 : f_internal_error_pipe = std::make_shared<capture_output_pipe>(this, f_error);
2183 1 : f_prepared_error = f_internal_error_pipe->get_other_socket();
2184 1 : f_communicator->add_connection(f_internal_error_pipe);
2185 1 : return;
2186 : }
2187 :
2188 : // as a fallback, pass our stderr
2189 : //
2190 7 : f_prepared_error = STDERR_FILENO;
2191 : }
2192 :
2193 :
2194 :
2195 : /** \brief Send the specified signal to this process.
2196 : *
2197 : * When the process is running, it is possible to send it a signal using
2198 : * this function. The signal is sent immediately.
2199 : *
2200 : * \param[in] sig The signal to send to the child process.
2201 : *
2202 : * \return 0 if the signal was sent, -1 on error and errno is set.
2203 : */
2204 0 : int process::kill(int sig)
2205 : {
2206 0 : if(f_child != -1
2207 0 : && f_running)
2208 : {
2209 0 : return ::kill(f_child, sig);
2210 : }
2211 :
2212 0 : errno = ESRCH;
2213 0 : return -1;
2214 : }
2215 :
2216 :
2217 : /** \brief Set process done callback.
2218 : *
2219 : * This function lets you define a callback which gets called whenever the
2220 : * SIGCHLD happens on that process.
2221 : *
2222 : * \warning
2223 : * At the time this function is called, the output is not likely to be
2224 : * ready. In most cases, the output buffer gets flushed only at the time
2225 : * the process exits and therefore the output on our end not yet ready.
2226 : * If you are interested in the output, make sure to use the
2227 : * set_output_capture_done() function when you want to get the final
2228 : * output.
2229 : *
2230 : * \param[in] callback The callback to call when SIGCHLD is received.
2231 : */
2232 0 : void process::set_process_done(process_done_t callback)
2233 : {
2234 0 : f_process_done = callback;
2235 0 : }
2236 :
2237 :
2238 : /** \brief Call this function once down with the output pipe.
2239 : *
2240 : * This function will remove the intermediate output pipe from the
2241 : * communicator. This pipe is an internal pipe created when you don't
2242 : * specify your own.
2243 : *
2244 : * We call this function as soon as we get an error or HUP in the
2245 : * pipe managed internally.
2246 : */
2247 3 : void process::input_pipe_done()
2248 : {
2249 3 : if(f_internal_input_pipe != nullptr)
2250 : {
2251 3 : f_communicator->remove_connection(f_internal_input_pipe);
2252 3 : f_internal_input_pipe->close();
2253 3 : f_internal_input_pipe.reset();
2254 : }
2255 3 : }
2256 :
2257 :
2258 : /** \brief Call this function once down with the output or error pipe.
2259 : *
2260 : * This function will remove the intermediate output pipe from the
2261 : * communicator. This pipe is an internal pipe created when you don't
2262 : * specify your own.
2263 : *
2264 : * We call this function as soon as we get an error or HUP in the
2265 : * pipe managed internally.
2266 : *
2267 : * \param[in] p The pipe being closed.
2268 : */
2269 4 : void process::output_pipe_done(ed::pipe_connection * p)
2270 : {
2271 4 : if(f_intermediate_output_pipe.get() == p)
2272 : {
2273 3 : f_communicator->remove_connection(f_intermediate_output_pipe);
2274 3 : f_intermediate_output_pipe->close();
2275 3 : f_intermediate_output_pipe.reset();
2276 :
2277 3 : if(f_output_done_callback != nullptr)
2278 : {
2279 0 : f_output_done_callback(get_output());
2280 : }
2281 : }
2282 1 : else if(f_internal_error_pipe.get() == p)
2283 : {
2284 1 : f_communicator->remove_connection(f_internal_error_pipe);
2285 1 : f_internal_error_pipe->close();
2286 1 : f_internal_error_pipe.reset();
2287 :
2288 1 : if(f_output_done_callback != nullptr)
2289 : {
2290 0 : f_error_done_callback(get_error());
2291 : }
2292 : }
2293 0 : else if(f_next.size() == 1)
2294 : {
2295 : // for the tee, we're not internally responsible for final output
2296 : // pipes, but when only one we want to take care of it here
2297 : //
2298 0 : pointer_t n(*f_next.begin());
2299 0 : while(n->f_next.size() != 0)
2300 : {
2301 0 : if(n->f_next.size() != 1)
2302 : {
2303 0 : return;
2304 : }
2305 0 : n = *n->f_next.begin();
2306 : }
2307 0 : if(n->f_intermediate_output_pipe.get() == p)
2308 : {
2309 0 : f_communicator->remove_connection(n->f_intermediate_output_pipe);
2310 0 : n->f_intermediate_output_pipe->close();
2311 0 : n->f_intermediate_output_pipe.reset();
2312 : }
2313 : }
2314 : }
2315 :
2316 :
2317 :
2318 6 : } // namespace cppprocess
2319 : // vim: ts=4 sw=4 et
|