do not indent boost unittest structurals
[libi2ncommon] / src / pipestream.cpp
CommitLineData
7e606af5
GE
1 /*
2The software in this package is distributed under the GNU General
3Public License version 2 (with a special exception described below).
4
5A copy of GNU General Public License (GPL) is included in this distribution,
6in the file COPYING.GPL.
7
8As a special exception, if other files instantiate templates or use macros
9or inline functions from this file, or you compile this file and link it
10with other works to produce a work based on this file, this file
11does not by itself cause the resulting work to be covered
12by the GNU General Public License.
13
14However the source code for this file must still be made available
15in accordance with section (3) of the GNU General Public License.
16
17This exception does not invalidate any other reasons why a work based
18on this file might be covered by the GNU General Public License.
19*/
20/***************************************************************************
21 inpipestream.cpp - C++ streambuffer wrapper
22 -------------------
23 begin : Thu Dec 27 2001
24 copyright : (C) 2001 by Intra2net AG
25 ***************************************************************************/
26
9e322fb7 27#include <errno.h>
7e606af5 28#include <stdio.h>
9e322fb7 29#include <string.h>
ff5191e6 30#include <fcntl.h>
f8f119bf 31#include <sys/wait.h>
9e322fb7 32#include <unistd.h>
7e606af5 33
7e606af5
GE
34#include <streambuf>
35#include <istream>
36#include <ostream>
37#include <cstdio>
9e322fb7
PG
38#include <boost/foreach.hpp>
39#include <boost/shared_array.hpp>
7e606af5
GE
40
41#include "exception.hxx"
9e322fb7 42#include "stringfunc.hxx"
7e606af5
GE
43#include "pipestream.hxx"
44
f8f119bf
GE
45/** @brief runs command and returns it's output as string
46 * @param command the full command with all parameters
47 * @param rescode struct containing the return code, if the program exited normally and so on
825c519f 48 * @param flags runtime control flags (stdio streams, environment, path lookup).
f8f119bf
GE
49 * @returns the output (stdout) of the called program
50 */
9e322fb7 51template <typename CmdT>
cc917897 52std::string capture_exec(CmdT command, ExecResult &rescode,
825c519f 53 const int flags)
f8f119bf
GE
54{
55 std::string output;
56
1d7539d5 57 bool exit_set = false;
f8f119bf
GE
58 int exit_status_waitpid;
59
60 // set the results to false until we are sure we have proper values
61 rescode.normal_exit = false;
62 rescode.terminated_by_signal = false;
63
64 try
65 {
66 {
825c519f 67 inpipestream ips(command, flags);
f8f119bf
GE
68
69 ips.store_exit_status(&exit_set, &exit_status_waitpid);
70
71 char buffer[2048];
72 while (ips.good())
73 {
74 ips.read(buffer, sizeof(buffer));
75 output.append(buffer, ips.gcount());
76 }
77 }
78
79 // exit_status_waitpid only valid after destruction of the inpipestream
80
81 if (exit_set)
82 {
83 rescode.normal_exit = WIFEXITED(exit_status_waitpid);
84 if (rescode.normal_exit)
85 rescode.return_code = WEXITSTATUS(exit_status_waitpid);
86
87 rescode.terminated_by_signal = WIFSIGNALED(exit_status_waitpid);
88 if (rescode.terminated_by_signal)
89 rescode.signal = WTERMSIG(exit_status_waitpid);
90 }
91 }
92 catch (pipestream_error &e)
93 {
94 rescode.error_message = e.what();
95 }
96
97 return output;
98}
99
cc917897
PG
100/** @brief Instantiation of \c capture_exec for STL string arguments.
101 * Caveat emptor: this will cause the backing stream to use \c
102 * popen(3). To avoid shelling out, please refer to one of the
103 * variants that allow passing an argument list.
104 *
105 * @param command String specifying the shell expression to be executed.
106 * @param res (Out parameter) Store information about the termination
107 * state in this struct.
108 *
109 * @returns Result of \c stdout. Note that due to the use of \c
110 * popen, the correct way to collect stderr output as
111 * well is to use shell redirection inside the expression
112 * passed.
113 */
9e322fb7 114std::string capture_exec (const std::string &command, ExecResult &res)
825c519f 115{ return capture_exec<const std::string &>(command, res, capture_flag::dflt); }
cc917897
PG
116
117/** @brief Instantiation of \c capture_exec for argument lists. The
118 * pipestream used to run the command will not shell out.
119 * One of \c out or \c err must be set.
120 *
121 * @param command List of \c char* specifying the \c argv array of the
122 * command to run. Note that the binary to executed is
123 * assumed to be present at index 0 and that the input
124 * is properly \c NULL terminated.
125 * @param res (Out parameter) Store information about the termination
126 * state in this struct.
825c519f
PG
127 * @param flags Runtime control flags (stdio streams, environment, path
128 * lookup).
cc917897
PG
129 *
130 * @returns Captured output, combined into one string.
131 */
132std::string capture_exec (const char *const *command, ExecResult &res,
825c519f
PG
133 const int flags)
134{ return capture_exec<const char *const *>(command, res, flags); }
cc917897
PG
135
136/** @brief Instantiation of \c capture_exec for argument lists. The
137 * pipestream used to run the command will not shell out.
138 * One of \c out or \c err must be set.
139 *
140 * @param command String vector specifying the \c argv array of the
141 * command to run. Note that the binary to executed is
142 * assumed to be present at index 0.
143 * @param res (Out parameter) Store information about the termination
144 * state in this struct.
825c519f
PG
145 * @param flags Runtime control flags (stdio streams, environment, path
146 * lookup).
cc917897
PG
147 *
148 * @returns Captured output, combined into one string.
149 */
150std::string capture_exec (const std::vector<std::string> &command, ExecResult &res,
825c519f
PG
151 const int flags)
152{ return capture_exec<const std::vector<std::string> &> (command, res, flags); }
c2c29997 153
9e322fb7
PG
154#define PIPE_CTOR_FAIL(where) \
155 do { \
156 throw EXCEPTION (pipestream_error, \
157 std::string (where) + ": error " \
158 + I2n::to_string (errno) \
159 + " (" + std::string (strerror (errno)) + ")"); \
160 } while (0)
161
cc917897
PG
162/** @brief Convert a string vector to a refcounted \c char**
163 * that is \c NULL terminated for use with e. g. \c execve(2).
164 *
165 * @param command List of arguments including the binary at index 0.
166 *
167 * @returns A \c boost::shared_array of pointers to the
168 * arguments plus a trailing \c NULL. Note that
169 * while the array itself is refcounted, the
170 * pointees are assumed owned by the caller and
171 * *not copyied*. I. e. they lose validity if the
172 * original strings are freed.
173 */
9e322fb7
PG
174static boost::shared_array <char *>
175mk_argv (const std::vector<std::string> &command)
176{
177 char **ret = NULL;
178
179 try {
180 ret = new char *[command.size () * sizeof (ret[0]) + 1];
181 } catch (std::bad_alloc &) {
182 return boost::shared_array<char *> ();
183 }
184
185 size_t cur = 0;
186 BOOST_FOREACH(const std::string &arg, command) {
187 /*
188 * Casting away constness is safe since the data is always
189 * kept alive until after exec().
190 */
191 ret [cur++] = const_cast<char *> (arg.c_str ());
192 }
193
194 ret [cur] = NULL;
195
196 return boost::shared_array<char *> (ret);
197}
198
ff5191e6
PG
199/** @brief Helper for redirecting a file descriptor to \c /dev/null.
200 * This will only acquire an fd the first time it is called
201 * or if it is called after unsuccessfully attempting to
202 * acquire one.
203 *
204 * @param fd The open file descriptor to operate on.
08199c66 205 * @param save_errno Out parameter: stores errno here after a syscall failure.
ff5191e6
PG
206 *
207 * @returns \c true on success, \c false otherwise (the call to
08199c66
PG
208 * either \c open(2) or \c dup2(2) failed), with errno
209 * communicated through saved_errno.
ff5191e6
PG
210 */
211static bool
08199c66 212redirect_devnull (const int fd, int &save_errno)
ff5191e6
PG
213{
214 static int nullfd = -1;
215
216 errno = 0;
217 if (nullfd == -1 && (nullfd = open ("/dev/null", O_RDWR)) == -1) {
08199c66 218 save_errno = errno;
ff5191e6
PG
219 return false;
220 }
221
222 errno = 0;
223 if (dup2 (nullfd, fd) == -1) {
08199c66 224 save_errno = errno;
ff5191e6
PG
225 return false;
226 }
227
228 return true;
229}
230
cc917897
PG
231/** @brief Helper aggregating common code for the shell-free ctors.
232 *
233 * @param argv Argument list prepared for \c execve(2).
825c519f
PG
234 * @param flags Control the runtime behavior wrt. stdio streams, \c
235 * *envp, and path search. One of \c collect_out or
236 * \c collect_err is mandatory. All other flags are
237 * optional. Pipebuf creation with fail with \c EINVAL
238 * if that constraint is violated.
cc917897
PG
239 *
240 * @returns A \c FILE* handle for streaming if successful, \c NULL
241 * otherwise.
825c519f
PG
242 *
243 * Error handling strategy:
244 *
245 * - receive all errors from child as ints through a cloexec pipe;
246 * - in the child, write error conditions always to pipe first,
247 * then try to emit a more verbose log message;
248 * - in the parent, throw on error indicating the child errno.
249 *
250 * Note that the error-pipe approach is robust due to guarantees by both
251 * standard (POSIX) and implementation (Linux) of pipes: The read(2) from
252 * the error channel will block until the pipe is either closed or written to;
253 * hence no need to check for EAGAIN. Those writes are guaranteed to be atomic
254 * because sizeof(errno) is less than PIPE_BUF; hence we can disregard EINTR. A
255 * pipe whose write end (i.e. in the child) has been closed (by the kernel
256 * because execve(2) was successful) will always indicate EOF by returning
257 * zero, hence we know precisely whether everything went well or not. Cf.
258 * pipe(7), sections “I/O on pipes and FIFOs” and “PIPE_BUF”, as well as
259 * Kerrisk (2010), section 44.10, p. 917f.
cc917897 260 */
17b459b3 261std::pair <pid_t, FILE *>
cc917897 262inpipebuf::init_without_shell (const char *const *argv,
825c519f 263 const int flags) const
9e322fb7
PG
264{
265 FILE *pipeobj = NULL;
08199c66
PG
266 int pipefd [2]; /* for reading output from the child */
267 int errfd [2]; /* for determining a successful exec() */
f2da42aa 268 sigset_t oldmask, newmask;
825c519f 269 char *const *envp = flags & capture_flag::env_passthru ? environ : NULL;
9e322fb7 270
825c519f
PG
271 if (!(flags & capture_flag::collect_any))
272 {
cc917897
PG
273 errno = EINVAL;
274 PIPE_CTOR_FAIL("ctor");
275 }
276
825c519f
PG
277 /*
278 * The error pipe must be openend with *O_CLOEXEC* set. We also open
279 * the data pipe with close-on-exec and remove that bit only in the child.
280 * The rationale is preventing the read fd from passed on if the parent
281 * later re-forks another child: we intend it to be read from this (master)
282 * process alone.
283 */
9e322fb7 284 errno = 0;
08199c66
PG
285 if ( ::pipe2 (pipefd, O_CLOEXEC) == -1
286 || ::pipe2 (errfd , O_CLOEXEC) == -1) {
a30f9a22 287 PIPE_CTOR_FAIL("pipe2");
9e322fb7
PG
288 }
289
f2da42aa
PG
290 sigfillset (&newmask);
291 sigprocmask (SIG_SETMASK, &newmask, &oldmask);
292
9e322fb7
PG
293 errno = 0;
294 pid_t childpid = fork ();
295 switch (childpid) {
296 case -1: {
f2da42aa 297 sigprocmask (SIG_SETMASK, &oldmask, NULL);
9e322fb7
PG
298 PIPE_CTOR_FAIL("fork");
299 break;
300 }
301 case 0: {
825c519f
PG
302 /*
303 * Close read ends of error and data channels: the child is assumed
304 * to write exclusively.
305 */
9e322fb7 306 close (pipefd [0]);
08199c66 307 close (errfd [0]);
9e322fb7 308
825c519f
PG
309 /*
310 * Remove cloexec bit from the write end of the pipe (this is the
311 * only flag with F_SETFD).
312 */
a30f9a22
PG
313 fcntl (pipefd [1], F_SETFD, 0);
314
08199c66 315 int save_errno = 0;
825c519f
PG
316
317 /*
318 * Assign /dev/null if asked to close one of the streams, else
319 * dup() it onto the pipe.
320 */
321 if (!(flags & capture_flag::collect_out))
322 {
323 if (!redirect_devnull (STDOUT_FILENO, save_errno))
324 {
08199c66
PG
325 (void)write (errfd [1], (char *)&save_errno, sizeof(save_errno));
326 exit (EXIT_FAILURE);
ff5191e6 327 }
825c519f
PG
328 }
329 else if (dup2 (pipefd[1], STDOUT_FILENO) == -1)
330 {
08199c66
PG
331 (void)write (errfd [1], (char *)&save_errno, sizeof(save_errno));
332 exit (EXIT_FAILURE);
9e322fb7
PG
333 }
334
825c519f
PG
335 if (!(flags & capture_flag::collect_err))
336 {
337 if (!redirect_devnull (STDERR_FILENO, save_errno))
338 {
08199c66
PG
339 (void)write (errfd [1], (char *)&save_errno, sizeof(save_errno));
340 exit (EXIT_FAILURE);
ff5191e6 341 }
825c519f
PG
342 }
343 else if (dup2 (pipefd[1], STDERR_FILENO) == -1)
344 {
08199c66
PG
345 (void)write (errfd [1], (char *)&save_errno, sizeof(save_errno));
346 exit (EXIT_FAILURE);
9e322fb7
PG
347 }
348
825c519f
PG
349 /*
350 * Close the write end of the pipe now that we have dup()’ed it
351 * onto the stdio fds. The parent will now receive EOF on the pipe
352 * when these fds are both closed.
353 */
17b459b3
PG
354 close (pipefd [1]);
355
825c519f
PG
356 /*
357 * Stop blocking signals so the child starts out with a sane
358 * environment.
359 */
f2da42aa
PG
360 sigprocmask (SIG_SETMASK, &oldmask, NULL);
361
9e322fb7 362 errno = 0;
825c519f 363 if (flags & capture_flag::search_path) {
cdc166d2 364 execvpe (argv [0], const_cast <char *const *>(argv), envp);
ad4490f1 365 } else {
cdc166d2 366 execve (argv [0], const_cast <char *const *>(argv), envp);
9e322fb7 367 }
08199c66 368
825c519f
PG
369 /*
370 * At this point, the call to execv[p]e() failed. Thus the error
371 * pipe is still opened and we forward the errno through it.
372 */
08199c66
PG
373 (void)write (errfd [1], (char *)&errno, sizeof(errno));
374 exit (EXIT_FAILURE);
9e322fb7
PG
375 break;
376 }
377 default: {
9e322fb7
PG
378 break;
379 }
380 }
381
825c519f
PG
382 /*
383 * The parent is assumed to only consume data from either pipe, never
384 * write.
385 */
08199c66
PG
386 close (pipefd [1]);
387 close (errfd [1]);
388
389 /*
390 * Check whether the child exec()’ed by reading from the error pipe.
391 * The call to read(2) will block, uninterruptible due to signals being
392 * blocked. If all went well, the read(2) will return zero bytes and we can
393 * ditch the error channel.
394 *
395 * Otherwise either the read(2) failed or we actually received something
396 * through the error pipe. Both cases are treated as errors and cause an
397 * exit from the ctor.
398 */
399 char buf [sizeof (errno)];
400 int ret;
401 memset (buf, 0, sizeof (buf));
402 errno = 0;
403 if ((ret = read (errfd [0], buf, sizeof (buf))) != 0) {
404 close (pipefd [0]);
405 close (errfd [0]);
406 sigprocmask (SIG_SETMASK, &oldmask, NULL);
407 if (ret == - 1) {
408 /* read(2) failed */
409 PIPE_CTOR_FAIL("read");
410 } else {
411 /*
412 * We received data on the error channel indicating the child
413 * process never successfully exec()’ed. We grab the error code
414 * from the buffer and bail.
415 */
416 errno = *((int *)&buf[0]);
417 PIPE_CTOR_FAIL("child failed to exec()");
418 }
419 }
420
421 /*
422 * read(2) yielded zero bytes; it’s safe to use the pipe so close our end
423 * and continue.
424 */
425 close (errfd [0]);
426
427 sigprocmask (SIG_SETMASK, &oldmask, NULL);
428
429 errno = 0;
430 if ((pipeobj = fdopen (pipefd [0], "r")) == NULL) {
431 close (pipefd [0]);
432 PIPE_CTOR_FAIL("fdopen");
433 }
434
17b459b3 435 return std::make_pair (childpid, pipeobj);
9e322fb7
PG
436}
437
cc917897 438inpipebuf::inpipebuf(const char *const *command,
825c519f 439 const int flags)
9e322fb7 440 : pipe (NULL) /* brr: shadowing global ident */
17b459b3 441 , pid (-1)
9e322fb7
PG
442 , status_set (NULL)
443 , exit_status (NULL)
444{
445 if (command == NULL || command [0] == NULL) {
446 PIPE_CTOR_FAIL("command");
447 }
448
825c519f 449 std::pair <pid_t, FILE *> tmp = this->init_without_shell (command, flags);
17b459b3
PG
450 this->pid = tmp.first; /* no std::tie :/ */
451 this->pipe = tmp.second;
9e322fb7
PG
452
453 setg (&buffer, &buffer, &buffer);
454}
455
cc917897 456inpipebuf::inpipebuf(const std::vector<std::string> &command,
825c519f 457 const int flags)
c2c29997 458 : pipe (NULL) /* brr: shadowing global ident */
17b459b3 459 , pid (-1)
c2c29997
PG
460 , status_set (NULL)
461 , exit_status (NULL)
462{
463 if (command.empty ()) {
464 PIPE_CTOR_FAIL("command");
465 }
466
467 const boost::shared_array <char *> argv = mk_argv (command);
468 if (!argv) {
469 PIPE_CTOR_FAIL("malloc");
470 }
471
ad4490f1 472 std::pair <pid_t, FILE *> tmp =
825c519f 473 this->init_without_shell (argv.get (), flags);
17b459b3
PG
474 this->pid = tmp.first;
475 this->pipe = tmp.second;
c2c29997
PG
476
477 setg (&buffer, &buffer, &buffer);
478}
479
cc917897 480inpipebuf::inpipebuf(const std::string& command,
825c519f 481 const int _ignored_flags)
17b459b3
PG
482 : pid (-1)
483 , status_set (NULL)
484 , exit_status (NULL)
7e606af5 485{
7e606af5
GE
486 pipe = popen (command.c_str(), "r");
487 if (pipe == NULL)
488 throw EXCEPTION (pipestream_error, "can't open program or permission denied");
489
490 // force underflow
491 setg (&buffer, &buffer, &buffer);
492}
493
494inpipebuf::~inpipebuf()
495{
496 if (pipe != NULL) {
17b459b3 497 int status;
7e606af5 498
17b459b3 499 if (this->pid == -1)
d00589a0 500 {
17b459b3
PG
501 errno = 0;
502 status = pclose (pipe);
503 if (status != -1) {
504 if (exit_status != NULL) {
505 *exit_status = status;
506 if (status_set != NULL) {
507 *status_set = true;
508 }
509 }
510 }
511 }
512 else
513 {
514 errno = 0;
515 status = fclose (pipe);
516 if (status != EOF) {
517 if (exit_status != NULL) {
518 *exit_status = status; /* might be overwritten below */
519 if (status_set != NULL) {
520 *status_set = true;
521 }
522 }
523 }
524
525 errno = 0;
526 while (waitpid (this->pid, &status, 0) == -1) {
527 if (errno != EINTR) {
528 status = -1;
529 break;
530 }
531 }
532 if (status != 0 && exit_status != NULL) {
533 *exit_status = status; /* might overwrite pipe status above */
534 if (status_set != NULL) {
535 *status_set = true;
536 }
537 }
7e606af5
GE
538 }
539
540 pipe = NULL;
541 }
542}
543
544/** note: exit status only available after destruction */
545void inpipebuf::store_exit_status(bool *_status_set, int *_exit_status)
546{
547 status_set = _status_set;
548 exit_status = _exit_status;
549}
550
551inpipebuf::int_type inpipebuf::underflow()
552{
553 if (gptr() < egptr())
554 return traits_type::to_int_type(*gptr());
555
556 buffer = fgetc (pipe);
557 if (feof (pipe))
558 {
559 // ERROR or EOF
560 return EOF;
561 }
562
563 setg (&buffer, &buffer, &buffer+sizeof(char));
564
565 return traits_type::to_int_type(*gptr());
566}
567
7e606af5
GE
568outpipebuf::outpipebuf(const std::string& command)
569{
570 status_set = NULL;
571 exit_status = NULL;
572
573 pipe = popen (command.c_str(), "w");
574 if (pipe == NULL)
575 throw EXCEPTION (pipestream_error, "can't open program or permission denied");
576}
577
578outpipebuf::~outpipebuf()
579{
580 if (pipe != NULL) {
581 int pclose_exit = pclose (pipe);
582
d00589a0
GE
583 if (exit_status && pclose_exit != -1)
584 {
585 if (status_set)
586 *status_set = true;
7e606af5
GE
587 *exit_status = pclose_exit;
588 }
589
590 pipe = NULL;
591 }
592}
593
594/** note: exit status only available after destruction */
595void outpipebuf::store_exit_status(bool *_status_set, int *_exit_status)
596{
597 status_set = _status_set;
598 exit_status = _exit_status;
599}
600
601outpipebuf::int_type outpipebuf::overflow(int_type c)
602{
603 if (c != EOF)
604 {
605 if (fputc(c,pipe)==EOF)
606 return EOF;
607 }
608 return c;
609}
610
611std::streamsize outpipebuf::xsputn(const char* s, std::streamsize num)
612{
613 return fwrite(s,num,1,pipe);
614}