static void ParseCommandLine()

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.");
    }
  }
}