blob: 2d8bfc8abc1d4e8777211088464b2f3e78554465 [file] [log] [blame]
Václav Kubernát6d9357e2021-01-28 15:38:24 +01001/*
2 * Copyright (C) 2021 CESNET, https://photonics.cesnet.cz/
3 *
4 * Written by Václav Kubernát <kubernat@cesnet.cz>
5 *
6*/
7
8#include <boost/algorithm/string/join.hpp>
9#include <boost/process.hpp>
10#include <boost/process/extend.hpp>
11#include "exec.h"
12#include "log.h"
13#include "system_vars.h"
14
15void velia::utils::execAndWait(
16 velia::Log logger,
17 const std::string& program,
18 std::initializer_list<std::string> args,
19 std::string_view std_in,
20 const std::set<ExecOptions> opts)
21{
22 namespace bp = boost::process;
23 bp::pipe stdinPipe;
24 bp::ipstream stderrStream;
25
26 auto onExecSetup = [opts] (const auto&) {
27 if (opts.count(ExecOptions::DropRoot) == 1) {
28 if (getuid() == 0) {
29 if (setgid(NOBODY_GID) == -1) {
30 perror("couldn't drop root privileges");
31 exit(1);
32 }
33
34 if (setuid(NOBODY_UID) == -1) {
35 perror("couldn't drop root privileges");
36 exit(1);
37 }
38 }
39 }
40 };
41
42 logger->trace("exec: {} {}", program, boost::algorithm::join(args, " "));
43 bp::child c(
44 bp::search_path(program),
45 boost::process::args=std::move(args),
46 bp::std_in < stdinPipe, bp::std_out > bp::null, bp::std_err > stderrStream,
47 bp::extend::on_exec_setup=onExecSetup);
48
49 stdinPipe.write(std_in.data(), std_in.size());
50 stdinPipe.close();
51
52 c.wait();
53 logger->trace("{} exited", program);
54
55 if (c.exit_code()) {
56 std::istreambuf_iterator<char> begin(stderrStream), end;
57 std::string stderrOutput(begin, end);
58 logger->critical("{} ended with a non-zero exit code. stderr: {}", program, stderrOutput);
59
60 throw std::runtime_error(program + " returned non-zero exit code " + std::to_string(c.exit_code()));
61 }
62}