// 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 #include #include #include #include #include #include #include #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 after which the child process will be " "terminated with SIGTERM\n" " -k/--kill_delay in case timeout occurs, how long to wait " "before killing the child with SIGKILL\n" " -o/--stdout redirect stdout to a file\n" " -e/--stderr redirect stderr to a file\n" " -s/--stats 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 &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(args.size())) { opt.args.assign(args.begin() + optind, args.end()); } } void ParseOptions(int argc, char *argv[]) { std::vector 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); }