Replace inet_aton() with inet_pton() to parse IPs correctly (#8825)
[libi2ncommon] / src / pipestream.cpp
... / ...
CommitLineData
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
27#include <errno.h>
28#include <stdio.h>
29#include <string.h>
30#include <fcntl.h>
31#include <sys/wait.h>
32#include <unistd.h>
33
34#include <streambuf>
35#include <istream>
36#include <ostream>
37#include <cstdio>
38#include <boost/foreach.hpp>
39#include <boost/shared_array.hpp>
40
41#include "exception.hxx"
42#include "stringfunc.hxx"
43#include "pipestream.hxx"
44
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
48 * @param flags runtime control flags (stdio streams, environment, path lookup).
49 * @returns the output (stdout) of the called program
50 */
51template <typename CmdT>
52std::string capture_exec(CmdT command, ExecResult &rescode,
53 const int flags)
54{
55 std::string output;
56
57 bool exit_set = false;
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 {
67 inpipestream ips(command, flags);
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
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 */
114std::string capture_exec (const std::string &command, ExecResult &res)
115{ return capture_exec<const std::string &>(command, res, capture_flag::dflt); }
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.
127 * @param flags Runtime control flags (stdio streams, environment, path
128 * lookup).
129 *
130 * @returns Captured output, combined into one string.
131 */
132std::string capture_exec (const char *const *command, ExecResult &res,
133 const int flags)
134{ return capture_exec<const char *const *>(command, res, flags); }
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.
145 * @param flags Runtime control flags (stdio streams, environment, path
146 * lookup).
147 *
148 * @returns Captured output, combined into one string.
149 */
150std::string capture_exec (const std::vector<std::string> &command, ExecResult &res,
151 const int flags)
152{ return capture_exec<const std::vector<std::string> &> (command, res, flags); }
153
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
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 */
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
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.
205 * @param save_errno Out parameter: stores errno here after a syscall failure.
206 *
207 * @returns \c true on success, \c false otherwise (the call to
208 * either \c open(2) or \c dup2(2) failed), with errno
209 * communicated through saved_errno.
210 */
211static bool
212redirect_devnull (const int fd, int &save_errno)
213{
214 static int nullfd = -1;
215
216 errno = 0;
217 if (nullfd == -1 && (nullfd = open ("/dev/null", O_RDWR)) == -1) {
218 save_errno = errno;
219 return false;
220 }
221
222 errno = 0;
223 if (dup2 (nullfd, fd) == -1) {
224 save_errno = errno;
225 return false;
226 }
227
228 return true;
229}
230
231/** @brief Helper aggregating common code for the shell-free ctors.
232 *
233 * @param argv Argument list prepared for \c execve(2).
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.
239 *
240 * @returns A \c FILE* handle for streaming if successful, \c NULL
241 * otherwise.
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.
260 */
261std::pair <pid_t, FILE *>
262inpipebuf::init_without_shell (const char *const *argv,
263 const int flags) const
264{
265 FILE *pipeobj = NULL;
266 int pipefd [2]; /* for reading output from the child */
267 int errfd [2]; /* for determining a successful exec() */
268 sigset_t oldmask, newmask;
269 char *const *envp = flags & capture_flag::env_passthru ? environ : NULL;
270
271 if (!(flags & capture_flag::collect_any))
272 {
273 errno = EINVAL;
274 PIPE_CTOR_FAIL("ctor");
275 }
276
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 */
284 errno = 0;
285 if ( ::pipe2 (pipefd, O_CLOEXEC) == -1
286 || ::pipe2 (errfd , O_CLOEXEC) == -1) {
287 PIPE_CTOR_FAIL("pipe2");
288 }
289
290 sigfillset (&newmask);
291 sigprocmask (SIG_SETMASK, &newmask, &oldmask);
292
293 errno = 0;
294 pid_t childpid = fork ();
295 switch (childpid) {
296 case -1: {
297 sigprocmask (SIG_SETMASK, &oldmask, NULL);
298 PIPE_CTOR_FAIL("fork");
299 break;
300 }
301 case 0: {
302 /*
303 * Close read ends of error and data channels: the child is assumed
304 * to write exclusively.
305 */
306 close (pipefd [0]);
307 close (errfd [0]);
308
309 /*
310 * Remove cloexec bit from the write end of the pipe (this is the
311 * only flag with F_SETFD).
312 */
313 fcntl (pipefd [1], F_SETFD, 0);
314
315 /*
316 * Prevent the child from receiving more privileges than the
317 * parent. This concerns mainly suid binaries.
318 */
319 errno = 0;
320 if ( flags & capture_flag::no_new_privs
321 && prctl (PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1)
322 {
323 (void)write (errfd [1], (char *)&errno, sizeof(errno));
324 exit (EXIT_FAILURE);
325 }
326
327 int save_errno = 0;
328
329 /*
330 * Assign /dev/null if asked to close one of the streams, else
331 * dup() it onto the pipe.
332 */
333 if (!(flags & capture_flag::collect_out))
334 {
335 if (!redirect_devnull (STDOUT_FILENO, save_errno))
336 {
337 (void)write (errfd [1], (char *)&save_errno, sizeof(save_errno));
338 exit (EXIT_FAILURE);
339 }
340 }
341 else if (dup2 (pipefd[1], STDOUT_FILENO) == -1)
342 {
343 (void)write (errfd [1], (char *)&save_errno, sizeof(save_errno));
344 exit (EXIT_FAILURE);
345 }
346
347 if (!(flags & capture_flag::collect_err))
348 {
349 if (!redirect_devnull (STDERR_FILENO, save_errno))
350 {
351 (void)write (errfd [1], (char *)&save_errno, sizeof(save_errno));
352 exit (EXIT_FAILURE);
353 }
354 }
355 else if (dup2 (pipefd[1], STDERR_FILENO) == -1)
356 {
357 (void)write (errfd [1], (char *)&save_errno, sizeof(save_errno));
358 exit (EXIT_FAILURE);
359 }
360
361 /*
362 * Close the write end of the pipe now that we have dup()’ed it
363 * onto the stdio fds. The parent will now receive EOF on the pipe
364 * when these fds are both closed.
365 */
366 close (pipefd [1]);
367
368 /*
369 * Stop blocking signals so the child starts out with a sane
370 * environment.
371 */
372 sigprocmask (SIG_SETMASK, &oldmask, NULL);
373
374 errno = 0;
375 if (flags & capture_flag::search_path) {
376 execvpe (argv [0], const_cast <char *const *>(argv), envp);
377 } else {
378 execve (argv [0], const_cast <char *const *>(argv), envp);
379 }
380
381 /*
382 * At this point, the call to execv[p]e() failed. Thus the error
383 * pipe is still opened and we forward the errno through it.
384 */
385 (void)write (errfd [1], (char *)&errno, sizeof(errno));
386 exit (EXIT_FAILURE);
387 break;
388 }
389 default: {
390 break;
391 }
392 }
393
394 /*
395 * The parent is assumed to only consume data from either pipe, never
396 * write.
397 */
398 close (pipefd [1]);
399 close (errfd [1]);
400
401 /*
402 * Check whether the child exec()’ed by reading from the error pipe.
403 * The call to read(2) will block, uninterruptible due to signals being
404 * blocked. If all went well, the read(2) will return zero bytes and we can
405 * ditch the error channel.
406 *
407 * Otherwise either the read(2) failed or we actually received something
408 * through the error pipe. Both cases are treated as errors and cause an
409 * exit from the ctor.
410 */
411 char buf [sizeof (errno)];
412 int ret;
413 memset (buf, 0, sizeof (buf));
414 errno = 0;
415 if ((ret = read (errfd [0], buf, sizeof (buf))) != 0) {
416 close (pipefd [0]);
417 close (errfd [0]);
418 sigprocmask (SIG_SETMASK, &oldmask, NULL);
419 if (ret == - 1) {
420 /* read(2) failed */
421 PIPE_CTOR_FAIL("read");
422 } else {
423 /*
424 * We received data on the error channel indicating the child
425 * process never successfully exec()’ed. We grab the error code
426 * from the buffer and bail.
427 */
428 errno = *((int *)&buf[0]);
429 PIPE_CTOR_FAIL("child failed to exec()");
430 }
431 }
432
433 /*
434 * read(2) yielded zero bytes; it’s safe to use the pipe so close our end
435 * and continue.
436 */
437 close (errfd [0]);
438
439 sigprocmask (SIG_SETMASK, &oldmask, NULL);
440
441 errno = 0;
442 if ((pipeobj = fdopen (pipefd [0], "r")) == NULL) {
443 close (pipefd [0]);
444 PIPE_CTOR_FAIL("fdopen");
445 }
446
447 return std::make_pair (childpid, pipeobj);
448}
449
450inpipebuf::inpipebuf(const char *const *command,
451 const int flags)
452 : pipe (NULL) /* brr: shadowing global ident */
453 , pid (-1)
454 , status_set (NULL)
455 , exit_status (NULL)
456{
457 if (command == NULL || command [0] == NULL) {
458 PIPE_CTOR_FAIL("command");
459 }
460
461 std::pair <pid_t, FILE *> tmp = this->init_without_shell (command, flags);
462 this->pid = tmp.first; /* no std::tie :/ */
463 this->pipe = tmp.second;
464
465 setg (&buffer, &buffer, &buffer);
466}
467
468inpipebuf::inpipebuf(const std::vector<std::string> &command,
469 const int flags)
470 : pipe (NULL) /* brr: shadowing global ident */
471 , pid (-1)
472 , status_set (NULL)
473 , exit_status (NULL)
474{
475 if (command.empty ()) {
476 PIPE_CTOR_FAIL("command");
477 }
478
479 const boost::shared_array <char *> argv = mk_argv (command);
480 if (!argv) {
481 PIPE_CTOR_FAIL("malloc");
482 }
483
484 std::pair <pid_t, FILE *> tmp =
485 this->init_without_shell (argv.get (), flags);
486 this->pid = tmp.first;
487 this->pipe = tmp.second;
488
489 setg (&buffer, &buffer, &buffer);
490}
491
492inpipebuf::inpipebuf(const std::string& command,
493 const int _ignored_flags)
494 : pid (-1)
495 , status_set (NULL)
496 , exit_status (NULL)
497{
498 pipe = popen (command.c_str(), "r");
499 if (pipe == NULL)
500 throw EXCEPTION (pipestream_error, "can't open program or permission denied");
501
502 // force underflow
503 setg (&buffer, &buffer, &buffer);
504}
505
506inpipebuf::~inpipebuf()
507{
508 if (pipe != NULL) {
509 int status;
510
511 if (this->pid == -1)
512 {
513 errno = 0;
514 status = pclose (pipe);
515 if (status != -1) {
516 if (exit_status != NULL) {
517 *exit_status = status;
518 if (status_set != NULL) {
519 *status_set = true;
520 }
521 }
522 }
523 }
524 else
525 {
526 errno = 0;
527 status = fclose (pipe);
528 if (status != EOF) {
529 if (exit_status != NULL) {
530 *exit_status = status; /* might be overwritten below */
531 if (status_set != NULL) {
532 *status_set = true;
533 }
534 }
535 }
536
537 errno = 0;
538 while (waitpid (this->pid, &status, 0) == -1) {
539 if (errno != EINTR) {
540 status = -1;
541 break;
542 }
543 }
544 if (status != 0 && exit_status != NULL) {
545 *exit_status = status; /* might overwrite pipe status above */
546 if (status_set != NULL) {
547 *status_set = true;
548 }
549 }
550 }
551
552 pipe = NULL;
553 }
554}
555
556/** note: exit status only available after destruction */
557void inpipebuf::store_exit_status(bool *_status_set, int *_exit_status)
558{
559 status_set = _status_set;
560 exit_status = _exit_status;
561}
562
563inpipebuf::int_type inpipebuf::underflow()
564{
565 if (gptr() < egptr())
566 return traits_type::to_int_type(*gptr());
567
568 buffer = fgetc (pipe);
569 if (feof (pipe))
570 {
571 // ERROR or EOF
572 return EOF;
573 }
574
575 setg (&buffer, &buffer, &buffer+sizeof(char));
576
577 return traits_type::to_int_type(*gptr());
578}
579
580outpipebuf::outpipebuf(const std::string& command)
581{
582 status_set = NULL;
583 exit_status = NULL;
584
585 pipe = popen (command.c_str(), "w");
586 if (pipe == NULL)
587 throw EXCEPTION (pipestream_error, "can't open program or permission denied");
588}
589
590outpipebuf::~outpipebuf()
591{
592 if (pipe != NULL) {
593 int pclose_exit = pclose (pipe);
594
595 if (exit_status && pclose_exit != -1)
596 {
597 if (status_set)
598 *status_set = true;
599 *exit_status = pclose_exit;
600 }
601
602 pipe = NULL;
603 }
604}
605
606/** note: exit status only available after destruction */
607void outpipebuf::store_exit_status(bool *_status_set, int *_exit_status)
608{
609 status_set = _status_set;
610 exit_status = _exit_status;
611}
612
613outpipebuf::int_type outpipebuf::overflow(int_type c)
614{
615 if (c != EOF)
616 {
617 if (fputc(c,pipe)==EOF)
618 return EOF;
619 }
620 return c;
621}
622
623std::streamsize outpipebuf::xsputn(const char* s, std::streamsize num)
624{
625 return fwrite(s,num,1,pipe);
626}