|  | // Copyright 2017 The Bazel Authors. All rights reserved. | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //    http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  |  | 
|  | #include "src/main/tools/process-wrapper-options.h" | 
|  |  | 
|  | #include <getopt.h> | 
|  | #include <stdarg.h> | 
|  | #include <stdio.h> | 
|  | #include <stdlib.h> | 
|  | #include <unistd.h> | 
|  | #include <memory> | 
|  | #include <string> | 
|  | #include <vector> | 
|  |  | 
|  | #include "src/main/tools/logging.h" | 
|  |  | 
|  | struct Options opt; | 
|  |  | 
|  | // Print out a usage error. argc and argv are the argument counter and vector, | 
|  | // fmt is a format, string for the error message to print. | 
|  | static void Usage(char *program_name, const char *fmt, ...) { | 
|  | va_list ap; | 
|  | va_start(ap, fmt); | 
|  | vfprintf(stderr, fmt, ap); | 
|  | va_end(ap); | 
|  |  | 
|  | fprintf(stderr, "\nUsage: %s -- command arg1 @args\n", program_name); | 
|  | fprintf( | 
|  | stderr, | 
|  | "\nPossible arguments:\n" | 
|  | "  -t/--timeout <timeout>  timeout after which the child process will be " | 
|  | "terminated with SIGTERM\n" | 
|  | "  -k/--kill_delay <timeout>  in case timeout occurs, how long to wait " | 
|  | "before killing the child with SIGKILL\n" | 
|  | "  -o/--stdout <file>  redirect stdout to a file\n" | 
|  | "  -e/--stderr <file>  redirect stderr to a file\n" | 
|  | "  -s/--stats <file>  if set, write stats in protobuf format to a file\n" | 
|  | "  -d/--debug  if set, debug info will be printed\n" | 
|  | "  --  command to run inside sandbox, followed by arguments\n"); | 
|  | exit(EXIT_FAILURE); | 
|  | } | 
|  |  | 
|  | // Parses command line flags from an argv array and puts the results into the | 
|  | // global `opt` struct. | 
|  | static void ParseCommandLine(const std::vector<char *> &args) { | 
|  | static struct option long_options[] = { | 
|  | {"timeout", required_argument, 0, 't'}, | 
|  | {"kill_delay", required_argument, 0, 'k'}, | 
|  | {"stdout", required_argument, 0, 'o'}, | 
|  | {"stderr", required_argument, 0, 'e'}, | 
|  | {"stats", required_argument, 0, 's'}, | 
|  | {"debug", no_argument, 0, 'd'}, | 
|  | {0, 0, 0, 0}}; | 
|  | extern char *optarg; | 
|  | extern int optind, optopt; | 
|  | int c; | 
|  |  | 
|  | while ((c = getopt_long(args.size(), args.data(), "+:t:k:o:e:s:d", | 
|  | long_options, nullptr)) != -1) { | 
|  | switch (c) { | 
|  | case 't': | 
|  | if (sscanf(optarg, "%lf", &opt.timeout_secs) != 1) { | 
|  | Usage(args.front(), "Invalid timeout (-t) value: %s", optarg); | 
|  | } | 
|  | break; | 
|  | case 'k': | 
|  | if (sscanf(optarg, "%lf", &opt.kill_delay_secs) != 1) { | 
|  | Usage(args.front(), "Invalid kill delay (-k) value: %s", optarg); | 
|  | } | 
|  | break; | 
|  | case 'o': | 
|  | if (opt.stdout_path.empty()) { | 
|  | opt.stdout_path.assign(optarg); | 
|  | } else { | 
|  | Usage(args.front(), | 
|  | "Cannot redirect stdout (-o) to more than one destination."); | 
|  | } | 
|  | break; | 
|  | case 'e': | 
|  | if (opt.stderr_path.empty()) { | 
|  | opt.stderr_path.assign(optarg); | 
|  | } else { | 
|  | Usage(args.front(), | 
|  | "Cannot redirect stderr (-e) to more than one destination."); | 
|  | } | 
|  | break; | 
|  | case 's': | 
|  | if (opt.stats_path.empty()) { | 
|  | opt.stats_path.assign(optarg); | 
|  | } else { | 
|  | Usage(args.front(), | 
|  | "Cannot write stats (-s) to more than one destination."); | 
|  | } | 
|  | 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 (optind < static_cast<int>(args.size())) { | 
|  | opt.args.assign(args.begin() + optind, args.end()); | 
|  | } | 
|  | } | 
|  |  | 
|  | void ParseOptions(int argc, char *argv[]) { | 
|  | std::vector<char *> args(argv, argv + argc); | 
|  |  | 
|  | ParseCommandLine(args); | 
|  |  | 
|  | if (opt.args.empty()) { | 
|  | Usage(args.front(), "No command specified."); | 
|  | } | 
|  |  | 
|  | // argv[] passed to execve() must be a null-terminated array. | 
|  | opt.args.push_back(nullptr); | 
|  | } |