blob: 1d45a3f3bb22c175b7865468ecdcfe88ffe001e1 [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
Václav Kubernáte5691932021-02-18 04:05:45 +010015std::string velia::utils::execAndWait(
Václav Kubernát6d9357e2021-01-28 15:38:24 +010016 velia::Log logger,
Václav Kubernátde0e4e62021-02-08 17:46:14 +010017 const std::string& absolutePath,
Václav Kubernát6d9357e2021-01-28 15:38:24 +010018 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;
Václav Kubernáte5691932021-02-18 04:05:45 +010024 bp::ipstream stdoutStream;
Václav Kubernát6d9357e2021-01-28 15:38:24 +010025 bp::ipstream stderrStream;
26
27 auto onExecSetup = [opts] (const auto&) {
28 if (opts.count(ExecOptions::DropRoot) == 1) {
29 if (getuid() == 0) {
30 if (setgid(NOBODY_GID) == -1) {
31 perror("couldn't drop root privileges");
32 exit(1);
33 }
34
35 if (setuid(NOBODY_UID) == -1) {
36 perror("couldn't drop root privileges");
37 exit(1);
38 }
39 }
40 }
41 };
42
Václav Kubernátde0e4e62021-02-08 17:46:14 +010043 logger->trace("exec: {} {}", absolutePath, boost::algorithm::join(args, " "));
Václav Kubernát6d9357e2021-01-28 15:38:24 +010044 bp::child c(
Václav Kubernátde0e4e62021-02-08 17:46:14 +010045 absolutePath,
Václav Kubernát6d9357e2021-01-28 15:38:24 +010046 boost::process::args=std::move(args),
Václav Kubernáte5691932021-02-18 04:05:45 +010047 bp::std_in < stdinPipe, bp::std_out > stdoutStream, bp::std_err > stderrStream,
Václav Kubernát6d9357e2021-01-28 15:38:24 +010048 bp::extend::on_exec_setup=onExecSetup);
49
50 stdinPipe.write(std_in.data(), std_in.size());
51 stdinPipe.close();
52
53 c.wait();
Václav Kubernátde0e4e62021-02-08 17:46:14 +010054 logger->trace("{} exited", absolutePath);
Václav Kubernát6d9357e2021-01-28 15:38:24 +010055
56 if (c.exit_code()) {
57 std::istreambuf_iterator<char> begin(stderrStream), end;
58 std::string stderrOutput(begin, end);
Václav Kubernátde0e4e62021-02-08 17:46:14 +010059 logger->critical("{} ended with a non-zero exit code. stderr: {}", absolutePath, stderrOutput);
Václav Kubernát6d9357e2021-01-28 15:38:24 +010060
Václav Kubernátde0e4e62021-02-08 17:46:14 +010061 throw std::runtime_error(absolutePath + " returned non-zero exit code " + std::to_string(c.exit_code()));
Václav Kubernát6d9357e2021-01-28 15:38:24 +010062 }
Václav Kubernáte5691932021-02-18 04:05:45 +010063
64 std::istreambuf_iterator<char> begin(stdoutStream), end;
65 return {begin, end};
Václav Kubernát6d9357e2021-01-28 15:38:24 +010066}