in src/main/tools/linux-sandbox-options.cc [93:244]
static void ParseCommandLine(unique_ptr<vector<char *>> args) {
extern char *optarg;
extern int optind, optopt;
int c;
bool source_specified = false;
while ((c = getopt(args->size(), args->data(),
":W:T:t:il:L:w:e:M:m:S:h:HNRUD")) != -1) {
if (c != 'M' && c != 'm') source_specified = false;
switch (c) {
case 'W':
if (opt.working_dir.empty()) {
ValidateIsAbsolutePath(optarg, args->front(), static_cast<char>(c));
opt.working_dir.assign(optarg);
} else {
Usage(args->front(),
"Multiple working directories (-W) specified, expected one.");
}
break;
case 'T':
if (sscanf(optarg, "%d", &opt.timeout_secs) != 1 ||
opt.timeout_secs < 0) {
Usage(args->front(), "Invalid timeout (-T) value: %s", optarg);
}
break;
case 't':
if (sscanf(optarg, "%d", &opt.kill_delay_secs) != 1 ||
opt.kill_delay_secs < 0) {
Usage(args->front(), "Invalid kill delay (-t) value: %s", optarg);
}
break;
case 'i':
opt.sigint_sends_sigterm = true;
break;
case 'l':
if (opt.stdout_path.empty()) {
opt.stdout_path.assign(optarg);
} else {
Usage(args->front(),
"Cannot redirect stdout to more than one destination.");
}
break;
case 'L':
if (opt.stderr_path.empty()) {
opt.stderr_path.assign(optarg);
} else {
Usage(args->front(),
"Cannot redirect stderr to more than one destination.");
}
break;
case 'w':
ValidateIsAbsolutePath(optarg, args->front(), static_cast<char>(c));
opt.writable_files.emplace_back(optarg);
break;
case 'e':
ValidateIsAbsolutePath(optarg, args->front(), static_cast<char>(c));
opt.tmpfs_dirs.emplace_back(optarg);
break;
case 'M':
ValidateIsAbsolutePath(optarg, args->front(), static_cast<char>(c));
// Add the current source path to both source and target lists
opt.bind_mount_sources.emplace_back(optarg);
opt.bind_mount_targets.emplace_back(optarg);
source_specified = true;
break;
case 'm':
ValidateIsAbsolutePath(optarg, args->front(), static_cast<char>(c));
if (!source_specified) {
Usage(args->front(),
"The -m option must be strictly preceded by an -M option.");
}
opt.bind_mount_targets.pop_back();
opt.bind_mount_targets.emplace_back(optarg);
source_specified = false;
break;
case 'S':
if (opt.stats_path.empty()) {
opt.stats_path.assign(optarg);
} else {
Usage(args->front(),
"Cannot write stats to more than one destination.");
}
break;
case 'h':
opt.hermetic = true;
if (opt.sandbox_root.empty()) {
std::string sandbox_root(optarg);
// Make sure that the sandbox_root path has no trailing slash.
if (sandbox_root.back() == '/') {
ValidateIsAbsolutePath(optarg, args->front(), static_cast<char>(c));
opt.sandbox_root.assign(sandbox_root, 0, sandbox_root.length() - 1);
if (opt.sandbox_root.back() == '/') {
Usage(args->front(),
"Sandbox root path should not have trailing slashes");
}
} else {
opt.sandbox_root.assign(sandbox_root);
}
} else {
Usage(args->front(),
"Multiple sandbox roots (-s) specified, expected one.");
}
break;
case 'H':
opt.fake_hostname = true;
break;
case 'N':
opt.create_netns = true;
break;
case 'R':
if (opt.fake_username) {
Usage(args->front(),
"The -R option cannot be used at the same time us the -U "
"option.");
}
opt.fake_root = true;
break;
case 'U':
if (opt.fake_root) {
Usage(args->front(),
"The -U option cannot be used at the same time us the -R "
"option.");
}
opt.fake_username = true;
break;
case 'D':
opt.debug = true;
break;
case '?':
Usage(args->front(), "Unrecognized argument: -%c (%d)", optopt, optind);
break;
case ':':
Usage(args->front(), "Flag -%c requires an argument", optopt);
break;
}
}
if (!opt.working_dir.empty() && !opt.sandbox_root.empty() &&
opt.working_dir.find(opt.sandbox_root) == std::string::npos) {
Usage(args->front(),
"working-dir %s (-W) should be a "
"subdirectory of sandbox-dir %s (-h)",
opt.working_dir.c_str(), opt.sandbox_root.c_str());
}
if (optind < static_cast<int>(args->size())) {
if (opt.args.empty()) {
opt.args.assign(args->begin() + optind, args->end());
} else {
Usage(args->front(), "Merging commands not supported.");
}
}
}