OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 The Crashpad Authors. All rights reserved. |
| 2 // |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 // you may not use this file except in compliance with the License. |
| 5 // You may obtain a copy of the License at |
| 6 // |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 // |
| 9 // Unless required by applicable law or agreed to in writing, software |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 // See the License for the specific language governing permissions and |
| 13 // limitations under the License. |
| 14 |
| 15 #include <errno.h> |
| 16 #include <getopt.h> |
| 17 #include <libgen.h> |
| 18 #include <stdio.h> |
| 19 #include <stdlib.h> |
| 20 #include <unistd.h> |
| 21 |
| 22 #include <string> |
| 23 #include <vector> |
| 24 |
| 25 #include "base/files/file_path.h" |
| 26 #include "base/logging.h" |
| 27 #include "client/crashpad_client.h" |
| 28 #include "tools/tool_support.h" |
| 29 |
| 30 namespace crashpad { |
| 31 namespace { |
| 32 |
| 33 void Usage(const std::string& me) { |
| 34 fprintf(stderr, |
| 35 "Usage: %s [OPTION]... COMMAND [ARG]...\n" |
| 36 "Start a Crashpad handler and have it handle crashes from COMMAND.\n" |
| 37 "\n" |
| 38 " -h, --handler=HANDLER invoke HANDLER instead of crashpad_handler\n
" |
| 39 " -a, --handler-argument=ARGUMENT invoke the handler with ARGUMENT\n" |
| 40 " --help display this help and exit\n" |
| 41 " --version output version information and exit\n", |
| 42 me.c_str()); |
| 43 ToolSupport::UsageTail(me); |
| 44 } |
| 45 |
| 46 int RunWithCrashpadMain(int argc, char* argv[]) { |
| 47 const std::string me(basename(argv[0])); |
| 48 |
| 49 enum ExitCode { |
| 50 kExitSuccess = EXIT_SUCCESS, |
| 51 |
| 52 // To differentiate this tool’s errors from errors in the programs it execs, |
| 53 // use a high exit code for ordinary failures instead of EXIT_FAILURE. This |
| 54 // is the same rationale for using the distinct exit codes for exec |
| 55 // failures. |
| 56 kExitFailure = 125, |
| 57 |
| 58 // Like env, use exit code 126 if the program was found but could not be |
| 59 // invoked, and 127 if it could not be found. |
| 60 // http://pubs.opengroup.org/onlinepubs/9699919799/utilities/env.html |
| 61 kExitExecFailure = 126, |
| 62 kExitExecENOENT = 127, |
| 63 }; |
| 64 |
| 65 enum OptionFlags { |
| 66 // “Short” (single-character) options. |
| 67 kOptionHandler = 'h', |
| 68 kOptionHandlerArgument = 'a', |
| 69 |
| 70 // Long options without short equivalents. |
| 71 kOptionLastChar = 255, |
| 72 |
| 73 // Standard options. |
| 74 kOptionHelp = -2, |
| 75 kOptionVersion = -3, |
| 76 }; |
| 77 |
| 78 const struct option long_options[] = { |
| 79 {"handler", required_argument, nullptr, kOptionHandler}, |
| 80 {"handler-argument", required_argument, nullptr, kOptionHandlerArgument}, |
| 81 {"help", no_argument, nullptr, kOptionHelp}, |
| 82 {"version", no_argument, nullptr, kOptionVersion}, |
| 83 {nullptr, 0, nullptr, 0}, |
| 84 }; |
| 85 |
| 86 struct { |
| 87 std::string handler; |
| 88 std::vector<std::string> handler_arguments; |
| 89 } options = {}; |
| 90 options.handler = "crashpad_handler"; |
| 91 |
| 92 int opt; |
| 93 while ((opt = getopt_long(argc, argv, "+a:h:", long_options, nullptr)) != |
| 94 -1) { |
| 95 switch (opt) { |
| 96 case kOptionHandler: |
| 97 options.handler = optarg; |
| 98 break; |
| 99 case kOptionHandlerArgument: |
| 100 options.handler_arguments.push_back(optarg); |
| 101 break; |
| 102 case kOptionHelp: |
| 103 Usage(me); |
| 104 return kExitSuccess; |
| 105 case kOptionVersion: |
| 106 ToolSupport::Version(me); |
| 107 return kExitSuccess; |
| 108 default: |
| 109 ToolSupport::UsageHint(me, nullptr); |
| 110 return kExitFailure; |
| 111 } |
| 112 } |
| 113 argc -= optind; |
| 114 argv += optind; |
| 115 |
| 116 if (!argc) { |
| 117 ToolSupport::UsageHint(me, "COMMAND is required"); |
| 118 return kExitFailure; |
| 119 } |
| 120 |
| 121 // Start the handler process and direct exceptions to it. |
| 122 CrashpadClient crashpad_client; |
| 123 if (!crashpad_client.StartHandler(base::FilePath(options.handler), |
| 124 options.handler_arguments)) { |
| 125 return kExitFailure; |
| 126 } |
| 127 |
| 128 if (!crashpad_client.UseHandler()) { |
| 129 return kExitFailure; |
| 130 } |
| 131 |
| 132 // Using the remaining arguments, start a new program with the new exception |
| 133 // port in effect. |
| 134 execvp(argv[0], argv); |
| 135 PLOG(ERROR) << "execvp " << argv[0]; |
| 136 return errno == ENOENT ? kExitExecENOENT : kExitExecFailure; |
| 137 } |
| 138 |
| 139 } // namespace |
| 140 } // namespace crashpad |
| 141 |
| 142 int main(int argc, char* argv[]) { |
| 143 return crashpad::RunWithCrashpadMain(argc, argv); |
| 144 } |
OLD | NEW |