|
4 | 4 |
|
5 | 5 | #include "linyaps_box/container_ref.h" |
6 | 6 |
|
| 7 | +#include "linyaps_box/container_monitor.h" |
| 8 | +#include "linyaps_box/terminal.h" |
| 9 | +#include "linyaps_box/utils/file.h" |
7 | 10 | #include "linyaps_box/utils/log.h" |
| 11 | +#include "linyaps_box/utils/process.h" |
| 12 | +#include "linyaps_box/utils/session.h" |
| 13 | +#include "linyaps_box/utils/socket.h" |
| 14 | +#include "linyaps_box/utils/terminal.h" |
8 | 15 |
|
9 | 16 | #include <csignal> // IWYU pragma: keep |
10 | 17 | #include <utility> |
@@ -38,73 +45,110 @@ void linyaps_box::container_ref::kill(int signal) const |
38 | 45 | throw std::system_error(errno, std::system_category(), std::move(ss).str()); |
39 | 46 | } |
40 | 47 |
|
41 | | -void linyaps_box::container_ref::exec(const linyaps_box::config::process_t &process) |
| 48 | +auto linyaps_box::container_ref::exec(exec_container_option option) -> int |
42 | 49 | { |
43 | 50 | auto target = std::to_string(this->status().PID); |
44 | 51 |
|
45 | | - std::vector<const char *> argv{ |
46 | | - "nsenter", |
47 | | - "--target", |
48 | | - target.c_str(), |
49 | | - "--user", |
50 | | - "--mount", |
51 | | - "--pid", |
52 | | - "--no-fork", |
53 | | - // FIXME: |
54 | | - // Old nsenter command do not support --wdns, |
55 | | - // so we have to implement nsenter by ourself in the future. |
56 | | - "--preserve-credentials", |
57 | | - }; |
| 52 | + // TODO: support detach later |
| 53 | + utils::prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0); |
58 | 54 |
|
59 | | - for (const auto &arg : process.args) { |
60 | | - argv.push_back(arg.c_str()); |
| 55 | + std::optional<unixSocketClient> recv_socketpair; |
| 56 | + if (option.proc.terminal && !option.console_socket) { |
| 57 | + auto [socket1, socket2] = utils::socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0); |
| 58 | + option.console_socket = unixSocketClient{ std::move(socket1) }; |
| 59 | + recv_socketpair = unixSocketClient{ std::move(socket2) }; |
61 | 60 | } |
62 | | - argv.push_back(nullptr); |
63 | 61 |
|
64 | | - std::vector<const char *> c_env; |
65 | | - c_env.reserve(process.env.size()); |
66 | | - for (const auto &env : process.env) { |
67 | | - c_env.push_back(env.c_str()); |
| 62 | + auto child = fork(); |
| 63 | + if (child < 0) { |
| 64 | + throw std::system_error(errno, std::system_category(), "fork"); |
68 | 65 | } |
69 | | - c_env.push_back(nullptr); |
70 | | - |
71 | | - LINYAPS_BOX_DEBUG() << [&argv]() -> std::string { |
72 | | - auto result = std::accumulate(argv.cbegin(), |
73 | | - argv.cend() - 1, |
74 | | - std::string{ "args:[" }, |
75 | | - [](std::string init, const std::string &val) { |
76 | | - init += val; |
77 | | - init.push_back(' '); |
78 | | - return init; |
79 | | - }); |
80 | | - result.push_back(']'); |
81 | | - result.insert(0, "execvp nsenter with arguments: "); |
82 | | - return result; |
83 | | - }(); |
84 | 66 |
|
85 | | - // FIXME: |
86 | | - // We only handle the command arguments for now |
87 | | - // here are some other fields in process we need to consider: |
88 | | - // terminal |
89 | | - // console.height |
90 | | - // console.width |
91 | | - // cwd |
92 | | - // env |
93 | | - // rlimits |
94 | | - // apparmor_profile |
95 | | - // capabilities |
96 | | - // no_new_privileges |
97 | | - // oom_score_adj |
98 | | - |
99 | | - ::execvpe("nsenter", const_cast<char **>(argv.data()), const_cast<char **>(c_env.data())); |
| 67 | + if (child == 0) { |
| 68 | + // TODO: create terminal after rewrite exec. it should be created in the container namespace |
| 69 | + if (option.console_socket) { |
| 70 | + utils::setsid(); |
| 71 | + auto [master, slave] = create_pty_pair(); |
| 72 | + |
| 73 | + slave.setup_stdio(); |
| 74 | + // TODO: use fchown after we implement exec option `--user` |
| 75 | + slave.set_size({}); |
| 76 | + |
| 77 | + option.console_socket->send_fd(std::move(master).take()); |
| 78 | + option.console_socket.reset(); |
| 79 | + } |
| 80 | + |
| 81 | + std::vector<const char *> argv{ |
| 82 | + "nsenter", |
| 83 | + "--target", |
| 84 | + target.c_str(), |
| 85 | + "--user", |
| 86 | + "--mount", |
| 87 | + "--pid", |
| 88 | + // FIXME: |
| 89 | + // Old nsenter command do not support --wdns, |
| 90 | + // so we have to implement nsenter by ourself in the future. |
| 91 | + "--preserve-credentials", |
| 92 | + }; |
| 93 | + |
| 94 | + for (const auto &arg : option.proc.args) { |
| 95 | + argv.push_back(arg.c_str()); |
| 96 | + } |
| 97 | + argv.push_back(nullptr); |
| 98 | + |
| 99 | + std::vector<const char *> c_env; |
| 100 | + c_env.reserve(option.proc.env.size()); |
| 101 | + for (const auto &env : option.proc.env) { |
| 102 | + c_env.push_back(env.c_str()); |
| 103 | + } |
| 104 | + c_env.push_back(nullptr); |
100 | 105 |
|
101 | | - std::stringstream ss; |
102 | | - ss << "execvp nsenter with arguments:"; |
103 | | - for (const auto &arg : argv) { |
104 | | - ss << " " << arg; |
| 106 | + // FIXME: |
| 107 | + // We only handle the command arguments for now |
| 108 | + // here are some other fields in process we need to consider: |
| 109 | + // terminal |
| 110 | + // console.height |
| 111 | + // console.width |
| 112 | + // cwd |
| 113 | + // env |
| 114 | + // rlimits |
| 115 | + // apparmor_profile |
| 116 | + // capabilities |
| 117 | + // no_new_privileges |
| 118 | + // oom_score_adj |
| 119 | + |
| 120 | + ::execvpe("nsenter", const_cast<char **>(argv.data()), const_cast<char **>(c_env.data())); |
| 121 | + _exit(EXIT_FAILURE); |
105 | 122 | } |
106 | 123 |
|
107 | | - throw std::system_error(errno, std::system_category(), std::move(ss).str()); |
| 124 | + auto in = utils::file_descriptor{ utils::fileno(stdin), false }; |
| 125 | + auto out = utils::file_descriptor{ utils::fileno(stdout), false }; |
| 126 | + |
| 127 | + container_monitor monitor{ child }; |
| 128 | + |
| 129 | + [&recv_socketpair, &monitor, &in, &out]() { |
| 130 | + if (!recv_socketpair) { |
| 131 | + return; |
| 132 | + } |
| 133 | + |
| 134 | + LINYAPS_BOX_DEBUG() << "Container requires a terminal"; |
| 135 | + |
| 136 | + std::string payload; |
| 137 | + auto master = terminal_master{ recv_socketpair->recv_fd(payload) }; |
| 138 | + |
| 139 | + recv_socketpair->release(); |
| 140 | + |
| 141 | + in.set_nonblock(true); |
| 142 | + out.set_nonblock(true); |
| 143 | + |
| 144 | + monitor.enable_io_forwarding(std::move(master), in, out); |
| 145 | + }(); |
| 146 | + |
| 147 | + if (!monitor.enable_signal_forwarding()) { |
| 148 | + return 0; |
| 149 | + } |
| 150 | + |
| 151 | + return monitor.wait_container_exit(); |
108 | 152 | } |
109 | 153 |
|
110 | 154 | const linyaps_box::status_directory &linyaps_box::container_ref::status_dir() const |
|
0 commit comments