Better output formatting for --help

This commit is contained in:
okunz 2023-06-13 11:47:21 +02:00
parent e1402ed775
commit 924c8fa9f9
No known key found for this signature in database

View File

@ -42,6 +42,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include <cstddef>
#include <memory> #include <memory>
#include <sstream> #include <sstream>
#include <string> #include <string>
@ -58,10 +59,11 @@
namespace cmdline { namespace cmdline {
#define _LOG_DEFAULT_FILE "/var/log/nsjail.log" #define _LOG_DEFAULT_FILE "/var/log/nsjail.log"
#define _MAX_CONSOLE_OUTPUT_WIDTH 65
struct custom_option { struct custom_option {
struct option opt; struct option opt;
const char* descr; const char *descr;
}; };
// clang-format off // clang-format off
@ -69,10 +71,10 @@ struct custom_option custom_opts[] = {
{ { "help", no_argument, NULL, 'h' }, "Help plz.." }, { { "help", no_argument, NULL, 'h' }, "Help plz.." },
{ { "mode", required_argument, NULL, 'M' }, { { "mode", required_argument, NULL, 'M' },
"Execution mode (default: 'o' [MODE_STANDALONE_ONCE]):\n" "Execution mode (default: 'o' [MODE_STANDALONE_ONCE]):\n"
"\tl: Wait for connections on a TCP port (specified with --port) [MODE_LISTEN_TCP]\n" " l: [MODE_LISTEN_TCP]\n\tWait for connections on a TCP port (specified with --port)\n"
"\to: Launch a single process on the console using clone/execve [MODE_STANDALONE_ONCE]\n" " o: [MODE_STANDALONE_ONCE]\n\tLaunch a single process on the console using clone/execve\n"
"\te: Launch a single process on the console using execve [MODE_STANDALONE_EXECVE]\n" " e: [MODE_STANDALONE_EXECVE]\n\tLaunch a single process on the console using execve\n"
"\tr: Launch a single process on the console with clone/execve, keep doing it forever [MODE_STANDALONE_RERUN]" }, " r: [MODE_STANDALONE_RERUN]\n\tLaunch a single process on the console with clone/execve, keep doing it forever" },
{ { "config", required_argument, NULL, 'C' }, "Configuration file in the config.proto ProtoBuf format (see configs/ directory for examples)" }, { { "config", required_argument, NULL, 'C' }, "Configuration file in the config.proto ProtoBuf format (see configs/ directory for examples)" },
{ { "exec_file", required_argument, NULL, 'x' }, "File to exec (default: argv[0])" }, { { "exec_file", required_argument, NULL, 'x' }, "File to exec (default: argv[0])" },
{ { "execute_fd", no_argument, NULL, 0x0607 }, "Use execveat() to execute a file-descriptor instead of executing the binary path. In such case argv[0]/exec_file denotes a file path before mount namespacing" }, { { "execute_fd", no_argument, NULL, 0x0607 }, "Use execveat() to execute a file-descriptor instead of executing the binary path. In such case argv[0]/exec_file denotes a file path before mount namespacing" },
@ -172,11 +174,54 @@ struct custom_option custom_opts[] = {
}; };
// clang-format on // clang-format on
static const char* logYesNo(bool yes) { static const char *logYesNo(bool yes) { return (yes ? "true" : "false"); }
return (yes ? "true" : "false");
size_t GetConsoleLength(const std::string &str) {
int result = 0;
for (char c : str) {
if (c == '\t') {
result += 8;
} else {
++result;
}
}
return result;
} }
static void cmdlineOptUsage(struct custom_option* option) { std::string FormatLine(const std::string &line, size_t max_len = 80) {
std::string indent = line.substr(0, line.find_first_not_of(" \t"));
size_t indent_len = GetConsoleLength(indent);
size_t cursor = 0;
std::string formatted;
std::vector<std::string> words = util::strSplit(line.c_str(), ' ');
for (const auto &word : words) {
size_t wlen = GetConsoleLength(word);
std::string separator = cursor == 0 ? "" : " ";
size_t slen = GetConsoleLength(separator);
if (cursor != 0 && cursor + slen + wlen >= max_len) {
util::StrAppend(&formatted, "\n");
cursor = 0;
separator = indent;
slen = indent_len;
}
util::StrAppend(&formatted, "%s%s", separator.c_str(), word.c_str());
cursor += slen + wlen;
}
return formatted;
}
std::string FormatDescription(const char *descr) {
std::string formatted;
std::vector<std::string> lines = util::strSplit(descr, '\n');
for (const auto &line : lines) {
util::StrAppend(&formatted, "%s\n",
FormatLine(std::string("\t") + line).c_str());
}
return formatted;
}
static void cmdlineOptUsage(struct custom_option *option) {
if (option->opt.val < 0x80) { if (option->opt.val < 0x80) {
LOG_HELP_BOLD(" --%s%s%c %s", option->opt.name, "|-", option->opt.val, LOG_HELP_BOLD(" --%s%s%c %s", option->opt.name, "|-", option->opt.val,
option->opt.has_arg == required_argument ? "VALUE" : ""); option->opt.has_arg == required_argument ? "VALUE" : "");
@ -184,10 +229,10 @@ static void cmdlineOptUsage(struct custom_option* option) {
LOG_HELP_BOLD(" --%s %s", option->opt.name, LOG_HELP_BOLD(" --%s %s", option->opt.name,
option->opt.has_arg == required_argument ? "VALUE" : ""); option->opt.has_arg == required_argument ? "VALUE" : "");
} }
LOG_HELP("\t%s", option->descr); LOG_HELP("%s", FormatDescription(option->descr).c_str());
} }
static void cmdlineUsage(const char* pname) { static void cmdlineUsage(const char *pname) {
LOG_HELP_BOLD("Usage: %s [options] -- path_to_command [args]", pname); LOG_HELP_BOLD("Usage: %s [options] -- path_to_command [args]", pname);
LOG_HELP_BOLD("Options:"); LOG_HELP_BOLD("Options:");
for (size_t i = 0; i < ARR_SZ(custom_opts); i++) { for (size_t i = 0; i < ARR_SZ(custom_opts); i++) {
@ -204,20 +249,21 @@ static void cmdlineUsage(const char* pname) {
LOG_HELP_BOLD(" nsjail -Me --chroot / --disable_proc -- /bin/echo \"ABC\""); LOG_HELP_BOLD(" nsjail -Me --chroot / --disable_proc -- /bin/echo \"ABC\"");
} }
void addEnv(nsjconf_t* nsjconf, const std::string& env) { void addEnv(nsjconf_t *nsjconf, const std::string &env) {
if (env.find('=') != std::string::npos) { if (env.find('=') != std::string::npos) {
nsjconf->envs.push_back(env); nsjconf->envs.push_back(env);
return; return;
} }
char* e = getenv(env.c_str()); char *e = getenv(env.c_str());
if (!e) { if (!e) {
LOG_W("Requested to use the %s envar, but it's not set. It'll be ignored", QC(env)); LOG_W("Requested to use the %s envar, but it's not set. It'll be ignored",
QC(env));
return; return;
} }
nsjconf->envs.push_back(std::string(env).append("=").append(e)); nsjconf->envs.push_back(std::string(env).append("=").append(e));
} }
void logParams(nsjconf_t* nsjconf) { void logParams(nsjconf_t *nsjconf) {
switch (nsjconf->mode) { switch (nsjconf->mode) {
case MODE_LISTEN_TCP: case MODE_LISTEN_TCP:
LOG_I("Mode: LISTEN_TCP"); LOG_I("Mode: LISTEN_TCP");
@ -237,50 +283,56 @@ void logParams(nsjconf_t* nsjconf) {
} }
LOG_I( LOG_I(
"Jail parameters: hostname:'%s', chroot:%s, process:'%s', bind:[%s]:%d, " "Jail parameters: hostname:'%s', chroot:%s, process:'%s', "
"bind:[%s]:%d, "
"max_conns:%u, max_conns_per_ip:%u, time_limit:%" PRId64 "max_conns:%u, max_conns_per_ip:%u, time_limit:%" PRId64
", personality:%#lx, daemonize:%s, clone_newnet:%s, " ", personality:%#lx, daemonize:%s, clone_newnet:%s, "
"clone_newuser:%s, clone_newns:%s, clone_newpid:%s, clone_newipc:%s, clone_newuts:%s, " "clone_newuser:%s, clone_newns:%s, clone_newpid:%s, clone_newipc:%s, "
"clone_newcgroup:%s, clone_newtime:%s, keep_caps:%s, disable_no_new_privs:%s, " "clone_newuts:%s, "
"clone_newcgroup:%s, clone_newtime:%s, keep_caps:%s, "
"disable_no_new_privs:%s, "
"max_cpus:%zu", "max_cpus:%zu",
nsjconf->hostname.c_str(), QC(nsjconf->chroot), nsjconf->hostname.c_str(), QC(nsjconf->chroot),
nsjconf->exec_file.empty() ? nsjconf->argv[0].c_str() : nsjconf->exec_file.c_str(), nsjconf->exec_file.empty() ? nsjconf->argv[0].c_str()
nsjconf->bindhost.c_str(), nsjconf->port, nsjconf->max_conns, nsjconf->max_conns_per_ip, : nsjconf->exec_file.c_str(),
nsjconf->tlimit, nsjconf->personality, logYesNo(nsjconf->daemonize), nsjconf->bindhost.c_str(), nsjconf->port, nsjconf->max_conns,
logYesNo(nsjconf->clone_newnet), logYesNo(nsjconf->clone_newuser), nsjconf->max_conns_per_ip, nsjconf->tlimit, nsjconf->personality,
logYesNo(nsjconf->clone_newns), logYesNo(nsjconf->clone_newpid), logYesNo(nsjconf->daemonize), logYesNo(nsjconf->clone_newnet),
logYesNo(nsjconf->clone_newipc), logYesNo(nsjconf->clone_newuts), logYesNo(nsjconf->clone_newuser), logYesNo(nsjconf->clone_newns),
logYesNo(nsjconf->clone_newcgroup), logYesNo(nsjconf->clone_newtime), logYesNo(nsjconf->clone_newpid), logYesNo(nsjconf->clone_newipc),
logYesNo(nsjconf->keep_caps), logYesNo(nsjconf->disable_no_new_privs), logYesNo(nsjconf->clone_newuts), logYesNo(nsjconf->clone_newcgroup),
nsjconf->max_cpus); logYesNo(nsjconf->clone_newtime), logYesNo(nsjconf->keep_caps),
logYesNo(nsjconf->disable_no_new_privs), nsjconf->max_cpus);
for (const auto& p : nsjconf->mountpts) { for (const auto &p : nsjconf->mountpts) {
LOG_I( LOG_I("%s: %s", p.is_symlink ? "Symlink" : "Mount",
"%s: %s", p.is_symlink ? "Symlink" : "Mount", mnt::describeMountPt(p).c_str()); mnt::describeMountPt(p).c_str());
} }
for (const auto& uid : nsjconf->uids) { for (const auto &uid : nsjconf->uids) {
LOG_I("Uid map: inside_uid:%lu outside_uid:%lu count:%zu newuidmap:%s", LOG_I("Uid map: inside_uid:%lu outside_uid:%lu count:%zu newuidmap:%s",
(unsigned long)uid.inside_id, (unsigned long)uid.outside_id, uid.count, (unsigned long)uid.inside_id, (unsigned long)uid.outside_id,
uid.is_newidmap ? "true" : "false"); uid.count, uid.is_newidmap ? "true" : "false");
if (uid.outside_id == 0 && nsjconf->clone_newuser) { if (uid.outside_id == 0 && nsjconf->clone_newuser) {
LOG_W( LOG_W(
"Process will be UID/EUID=0 in the global user namespace, and will " "Process will be UID/EUID=0 in the global user namespace, and "
"will "
"have user root-level access to files"); "have user root-level access to files");
} }
} }
for (const auto& gid : nsjconf->gids) { for (const auto &gid : nsjconf->gids) {
LOG_I("Gid map: inside_gid:%lu outside_gid:%lu count:%zu newgidmap:%s", LOG_I("Gid map: inside_gid:%lu outside_gid:%lu count:%zu newgidmap:%s",
(unsigned long)gid.inside_id, (unsigned long)gid.outside_id, gid.count, (unsigned long)gid.inside_id, (unsigned long)gid.outside_id,
gid.is_newidmap ? "true" : "false"); gid.count, gid.is_newidmap ? "true" : "false");
if (gid.outside_id == 0 && nsjconf->clone_newuser) { if (gid.outside_id == 0 && nsjconf->clone_newuser) {
LOG_W( LOG_W(
"Process will be GID/EGID=0 in the global user namespace, and will " "Process will be GID/EGID=0 in the global user namespace, and "
"will "
"have group root-level access to files"); "have group root-level access to files");
} }
} }
} }
uint64_t parseRLimit(int res, const char* optarg, unsigned long mul) { uint64_t parseRLimit(int res, const char *optarg, unsigned long mul) {
if (strcasecmp(optarg, "inf") == 0) { if (strcasecmp(optarg, "inf") == 0) {
return RLIM64_INFINITY; return RLIM64_INFINITY;
} }
@ -296,7 +348,9 @@ uint64_t parseRLimit(int res, const char* optarg, unsigned long mul) {
} }
if (!util::isANumber(optarg)) { if (!util::isANumber(optarg)) {
LOG_F( LOG_F(
"RLIMIT %d needs a numeric or 'max'/'hard'/'def'/'soft'/'inf' value ('%s' " "RLIMIT %d needs a numeric or 'max'/'hard'/'def'/'soft'/'inf' "
"value "
"('%s' "
"provided)", "provided)",
res, optarg); res, optarg);
} }
@ -308,17 +362,17 @@ uint64_t parseRLimit(int res, const char* optarg, unsigned long mul) {
return val * mul; return val * mul;
} }
static std::string argFromVec(const std::vector<std::string>& vec, size_t pos) { static std::string argFromVec(const std::vector<std::string> &vec, size_t pos) {
if (pos >= vec.size()) { if (pos >= vec.size()) {
return ""; return "";
} }
return vec[pos]; return vec[pos];
} }
static bool setupArgv(nsjconf_t* nsjconf, int argc, char** argv, int optind) { static bool setupArgv(nsjconf_t *nsjconf, int argc, char **argv, int optind) {
/* /*
* If user provided cmdline via nsjail [opts] -- [cmdline], then override the one from the * If user provided cmdline via nsjail [opts] -- [cmdline], then override
* config file * the one from the config file
*/ */
if (optind < argc) { if (optind < argc) {
nsjconf->argv.clear(); nsjconf->argv.clear();
@ -326,7 +380,7 @@ static bool setupArgv(nsjconf_t* nsjconf, int argc, char** argv, int optind) {
nsjconf->argv.push_back(argv[i]); nsjconf->argv.push_back(argv[i]);
} }
} }
if (nsjconf->exec_file.empty() && nsjconf->argv.size() > 0) { if (nsjconf->exec_file.empty() && !nsjconf->argv.empty()) {
nsjconf->exec_file = nsjconf->argv[0]; nsjconf->exec_file = nsjconf->argv[0];
} }
if (nsjconf->exec_file.empty()) { if (nsjconf->exec_file.empty()) {
@ -338,12 +392,15 @@ static bool setupArgv(nsjconf_t* nsjconf, int argc, char** argv, int optind) {
if (nsjconf->use_execveat) { if (nsjconf->use_execveat) {
#if !defined(__NR_execveat) #if !defined(__NR_execveat)
LOG_E( LOG_E(
"Your nsjail is compiled without support for the execveat() syscall, yet you " "Your nsjail is compiled without support for the execveat() "
"syscall, "
"yet you "
"specified the --execute_fd flag"); "specified the --execute_fd flag");
return false; return false;
#endif /* !defined(__NR_execveat) */ #endif /* !defined(__NR_execveat) */
if ((nsjconf->exec_fd = TEMP_FAILURE_RETRY( if ((nsjconf->exec_fd = TEMP_FAILURE_RETRY(open(
open(nsjconf->exec_file.c_str(), O_RDONLY | O_PATH | O_CLOEXEC))) == -1) { nsjconf->exec_file.c_str(), O_RDONLY | O_PATH | O_CLOEXEC))) ==
-1) {
PLOG_W("Couldn't open %s file", QC(nsjconf->exec_file)); PLOG_W("Couldn't open %s file", QC(nsjconf->exec_file));
return false; return false;
} }
@ -351,18 +408,22 @@ static bool setupArgv(nsjconf_t* nsjconf, int argc, char** argv, int optind) {
return true; return true;
} }
static bool setupMounts(nsjconf_t* nsjconf) { static bool setupMounts(nsjconf_t *nsjconf) {
if (!(nsjconf->chroot.empty())) { if (!(nsjconf->chroot.empty())) {
if (!mnt::addMountPtHead(nsjconf, nsjconf->chroot, "/", /* fstype= */ "", if (!mnt::addMountPtHead(nsjconf, nsjconf->chroot, "/", /* fstype= */ "",
/* options= */ "", /* options= */ "",
nsjconf->is_root_rw ? (MS_BIND | MS_REC | MS_PRIVATE) nsjconf->is_root_rw
? (MS_BIND | MS_REC | MS_PRIVATE)
: (MS_BIND | MS_REC | MS_PRIVATE | MS_RDONLY), : (MS_BIND | MS_REC | MS_PRIVATE | MS_RDONLY),
/* is_dir= */ mnt::NS_DIR_YES, /* is_mandatory= */ true, /* src_env= */ "", /* is_dir= */ mnt::NS_DIR_YES,
/* dst_env= */ "", /* src_content= */ "", /* is_symlink= */ false)) { /* is_mandatory= */ true, /* src_env= */ "",
/* dst_env= */ "", /* src_content= */ "",
/* is_symlink= */ false)) {
return false; return false;
} }
} else { } else {
if (!mnt::addMountPtHead(nsjconf, /* src= */ "", "/", "tmpfs", if (!mnt::addMountPtHead(
nsjconf, /* src= */ "", "/", "tmpfs",
/* options= */ "", nsjconf->is_root_rw ? 0 : MS_RDONLY, /* options= */ "", nsjconf->is_root_rw ? 0 : MS_RDONLY,
/* is_dir= */ mnt::NS_DIR_YES, /* is_dir= */ mnt::NS_DIR_YES,
/* is_mandatory= */ true, /* src_env= */ "", /* dst_env= */ "", /* is_mandatory= */ true, /* src_env= */ "", /* dst_env= */ "",
@ -372,9 +433,12 @@ static bool setupMounts(nsjconf_t* nsjconf) {
} }
if (!nsjconf->proc_path.empty()) { if (!nsjconf->proc_path.empty()) {
if (!mnt::addMountPtTail(nsjconf, /* src= */ "", nsjconf->proc_path, "proc", if (!mnt::addMountPtTail(nsjconf, /* src= */ "", nsjconf->proc_path, "proc",
/* options= */ "", nsjconf->is_proc_rw ? 0 : MS_RDONLY, /* options= */ "",
/* is_dir= */ mnt::NS_DIR_YES, /* is_mandatory= */ true, /* src_env= */ "", nsjconf->is_proc_rw ? 0 : MS_RDONLY,
/* dst_env= */ "", /* src_content= */ "", /* is_symlink= */ false)) { /* is_dir= */ mnt::NS_DIR_YES,
/* is_mandatory= */ true, /* src_env= */ "",
/* dst_env= */ "", /* src_content= */ "",
/* is_symlink= */ false)) {
return false; return false;
} }
} }
@ -382,7 +446,7 @@ static bool setupMounts(nsjconf_t* nsjconf) {
return true; return true;
} }
void setupUsers(nsjconf_t* nsjconf) { void setupUsers(nsjconf_t *nsjconf) {
if (nsjconf->uids.empty()) { if (nsjconf->uids.empty()) {
idmap_t uid; idmap_t uid;
uid.inside_id = getuid(); uid.inside_id = getuid();
@ -401,9 +465,10 @@ void setupUsers(nsjconf_t* nsjconf) {
} }
} }
std::string parseMACVlanMode(const char* optarg) { std::string parseMACVlanMode(const char *optarg) {
if (strcasecmp(optarg, "private") != 0 && strcasecmp(optarg, "vepa") != 0 && if (strcasecmp(optarg, "private") != 0 && strcasecmp(optarg, "vepa") != 0 &&
strcasecmp(optarg, "bridge") != 0 && strcasecmp(optarg, "passthru") != 0) { strcasecmp(optarg, "bridge") != 0 &&
strcasecmp(optarg, "passthru") != 0) {
LOG_F( LOG_F(
"macvlan mode can only be one of the values: " "macvlan mode can only be one of the values: "
"'private'/'vepa'/'bridge'/'passthru' ('%s' " "'private'/'vepa'/'bridge'/'passthru' ('%s' "
@ -413,7 +478,7 @@ std::string parseMACVlanMode(const char* optarg) {
return std::string(optarg); return std::string(optarg);
} }
std::unique_ptr<nsjconf_t> parseArgs(int argc, char* argv[]) { std::unique_ptr<nsjconf_t> parseArgs(int argc, char *argv[]) {
std::unique_ptr<nsjconf_t> nsjconf(new nsjconf_t); std::unique_ptr<nsjconf_t> nsjconf(new nsjconf_t);
nsjconf->use_execveat = false; nsjconf->use_execveat = false;
@ -506,8 +571,10 @@ std::unique_ptr<nsjconf_t> parseArgs(int argc, char* argv[]) {
int opt_index = 0; int opt_index = 0;
for (;;) { for (;;) {
int c = getopt_long(argc, argv, int c = getopt_long(
"x:H:D:C:c:p:i:u:g:l:L:t:M:NdvqQeh?E:R:B:T:m:s:P:I:U:G:", opts, &opt_index); argc, argv,
"x:H:D:C:c:p:i:u:g:l:L:t:M:NdvqQeh?E:R:B:T:m:s:P:I:U:G:", opts,
&opt_index);
if (c == -1) { if (c == -1) {
break; break;
} }
@ -701,7 +768,8 @@ std::unique_ptr<nsjconf_t> parseArgs(int argc, char* argv[]) {
std::string o_id = argFromVec(subopts, 1); std::string o_id = argFromVec(subopts, 1);
std::string cnt = argFromVec(subopts, 2); std::string cnt = argFromVec(subopts, 2);
size_t count = strtoul(cnt.c_str(), nullptr, 0); size_t count = strtoul(cnt.c_str(), nullptr, 0);
if (!user::parseId(nsjconf.get(), i_id, o_id, count, /* is_gid= */ false, if (!user::parseId(nsjconf.get(), i_id, o_id, count,
/* is_gid= */ false,
/* is_newidmap= */ false)) { /* is_newidmap= */ false)) {
return nullptr; return nullptr;
} }
@ -712,7 +780,8 @@ std::unique_ptr<nsjconf_t> parseArgs(int argc, char* argv[]) {
std::string o_id = argFromVec(subopts, 1); std::string o_id = argFromVec(subopts, 1);
std::string cnt = argFromVec(subopts, 2); std::string cnt = argFromVec(subopts, 2);
size_t count = strtoul(cnt.c_str(), nullptr, 0); size_t count = strtoul(cnt.c_str(), nullptr, 0);
if (!user::parseId(nsjconf.get(), i_id, o_id, count, /* is_gid= */ true, if (!user::parseId(nsjconf.get(), i_id, o_id, count,
/* is_gid= */ true,
/* is_newidmap= */ false)) { /* is_newidmap= */ false)) {
return nullptr; return nullptr;
} }
@ -723,7 +792,8 @@ std::unique_ptr<nsjconf_t> parseArgs(int argc, char* argv[]) {
std::string o_id = argFromVec(subopts, 1); std::string o_id = argFromVec(subopts, 1);
std::string cnt = argFromVec(subopts, 2); std::string cnt = argFromVec(subopts, 2);
size_t count = strtoul(cnt.c_str(), nullptr, 0); size_t count = strtoul(cnt.c_str(), nullptr, 0);
if (!user::parseId(nsjconf.get(), i_id, o_id, count, /* is_gid= */ false, if (!user::parseId(nsjconf.get(), i_id, o_id, count,
/* is_gid= */ false,
/* is_newidmap= */ true)) { /* is_newidmap= */ true)) {
return nullptr; return nullptr;
} }
@ -734,7 +804,8 @@ std::unique_ptr<nsjconf_t> parseArgs(int argc, char* argv[]) {
std::string o_id = argFromVec(subopts, 1); std::string o_id = argFromVec(subopts, 1);
std::string cnt = argFromVec(subopts, 2); std::string cnt = argFromVec(subopts, 2);
size_t count = strtoul(cnt.c_str(), nullptr, 0); size_t count = strtoul(cnt.c_str(), nullptr, 0);
if (!user::parseId(nsjconf.get(), i_id, o_id, count, /* is_gid= */ true, if (!user::parseId(nsjconf.get(), i_id, o_id, count,
/* is_gid= */ true,
/* is_newidmap= */ true)) { /* is_newidmap= */ true)) {
return nullptr; return nullptr;
} }
@ -746,7 +817,8 @@ std::unique_ptr<nsjconf_t> parseArgs(int argc, char* argv[]) {
if (dst.empty()) { if (dst.empty()) {
dst = src; dst = src;
} }
if (!mnt::addMountPtTail(nsjconf.get(), src, dst, /* fstype= */ "", if (!mnt::addMountPtTail(
nsjconf.get(), src, dst, /* fstype= */ "",
/* options= */ "", MS_BIND | MS_REC | MS_PRIVATE | MS_RDONLY, /* options= */ "", MS_BIND | MS_REC | MS_PRIVATE | MS_RDONLY,
/* is_dir= */ mnt::NS_DIR_MAYBE, /* is_mandatory= */ true, /* is_dir= */ mnt::NS_DIR_MAYBE, /* is_mandatory= */ true,
/* src_env= */ "", /* dst_env= */ "", /* src_content= */ "", /* src_env= */ "", /* dst_env= */ "", /* src_content= */ "",
@ -761,7 +833,8 @@ std::unique_ptr<nsjconf_t> parseArgs(int argc, char* argv[]) {
if (dst.empty()) { if (dst.empty()) {
dst = src; dst = src;
} }
if (!mnt::addMountPtTail(nsjconf.get(), src, dst, /* fstype= */ "", if (!mnt::addMountPtTail(
nsjconf.get(), src, dst, /* fstype= */ "",
/* options= */ "", MS_BIND | MS_REC | MS_PRIVATE, /* options= */ "", MS_BIND | MS_REC | MS_PRIVATE,
/* is_dir= */ mnt::NS_DIR_MAYBE, /* is_mandatory= */ true, /* is_dir= */ mnt::NS_DIR_MAYBE, /* is_mandatory= */ true,
/* src_env= */ "", /* dst_env= */ "", /* src_content= */ "", /* src_env= */ "", /* dst_env= */ "", /* src_content= */ "",
@ -770,7 +843,8 @@ std::unique_ptr<nsjconf_t> parseArgs(int argc, char* argv[]) {
} }
}; break; }; break;
case 'T': { case 'T': {
if (!mnt::addMountPtTail(nsjconf.get(), "", optarg, /* fstype= */ "tmpfs", if (!mnt::addMountPtTail(
nsjconf.get(), "", optarg, /* fstype= */ "tmpfs",
/* options= */ "size=4194304", 0, /* options= */ "size=4194304", 0,
/* is_dir= */ mnt::NS_DIR_YES, /* is_mandatory= */ true, /* is_dir= */ mnt::NS_DIR_YES, /* is_mandatory= */ true,
/* src_env= */ "", /* dst_env= */ "", /* src_content= */ "", /* src_env= */ "", /* dst_env= */ "", /* src_content= */ "",
@ -792,7 +866,8 @@ std::unique_ptr<nsjconf_t> parseArgs(int argc, char* argv[]) {
optionsStream << ":" << subopts[i]; optionsStream << ":" << subopts[i];
} }
std::string options = optionsStream.str(); std::string options = optionsStream.str();
if (!mnt::addMountPtTail(nsjconf.get(), src, dst, /* fstype= */ fs_type, if (!mnt::addMountPtTail(
nsjconf.get(), src, dst, /* fstype= */ fs_type,
/* options= */ options, /* flags= */ 0, /* options= */ options, /* flags= */ 0,
/* is_dir= */ mnt::NS_DIR_MAYBE, /* is_mandatory= */ true, /* is_dir= */ mnt::NS_DIR_MAYBE, /* is_mandatory= */ true,
/* src_env= */ "", /* dst_env= */ "", /* src_content= */ "", /* src_env= */ "", /* dst_env= */ "", /* src_content= */ "",
@ -804,7 +879,8 @@ std::unique_ptr<nsjconf_t> parseArgs(int argc, char* argv[]) {
std::vector<std::string> subopts = util::strSplit(optarg, ':'); std::vector<std::string> subopts = util::strSplit(optarg, ':');
std::string src = argFromVec(subopts, 0); std::string src = argFromVec(subopts, 0);
std::string dst = argFromVec(subopts, 1); std::string dst = argFromVec(subopts, 1);
if (!mnt::addMountPtTail(nsjconf.get(), src, dst, /* fstype= */ "", if (!mnt::addMountPtTail(
nsjconf.get(), src, dst, /* fstype= */ "",
/* options= */ "", /* flags= */ 0, /* options= */ "", /* flags= */ 0,
/* is_dir= */ mnt::NS_DIR_NO, /* is_mandatory= */ true, /* is_dir= */ mnt::NS_DIR_NO, /* is_mandatory= */ true,
/* src_env= */ "", /* dst_env= */ "", /* src_content= */ "", /* src_env= */ "", /* dst_env= */ "", /* src_content= */ "",
@ -891,7 +967,8 @@ std::unique_ptr<nsjconf_t> parseArgs(int argc, char* argv[]) {
nsjconf->cgroup_pids_parent = optarg; nsjconf->cgroup_pids_parent = optarg;
break; break;
case 0x821: case 0x821:
nsjconf->cgroup_net_cls_classid = (unsigned int)strtoul(optarg, NULL, 0); nsjconf->cgroup_net_cls_classid =
(unsigned int)strtoul(optarg, NULL, 0);
break; break;
case 0x822: case 0x822:
nsjconf->cgroup_net_cls_mount = optarg; nsjconf->cgroup_net_cls_mount = optarg;