| 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 <CoreFoundation/CoreFoundation.h> | |
| 16 #import <Foundation/Foundation.h> | |
| 17 #include <getopt.h> | |
| 18 #include <launch.h> | |
| 19 #include <libgen.h> | |
| 20 #include <stdio.h> | |
| 21 #include <stdlib.h> | |
| 22 #include <unistd.h> | |
| 23 | |
| 24 #include <string> | |
| 25 #include <vector> | |
| 26 | |
| 27 #include "base/mac/foundation_util.h" | |
| 28 #include "base/strings/sys_string_conversions.h" | |
| 29 #include "tools/tool_support.h" | |
| 30 #include "util/mac/service_management.h" | |
| 31 #include "util/stdlib/objc.h" | |
| 32 | |
| 33 namespace crashpad { | |
| 34 namespace { | |
| 35 | |
| 36 void Usage(const std::string& me) { | |
| 37 fprintf(stderr, | |
| 38 "Usage: %s -L -l LABEL [OPTION]... COMMAND [ARG]...\n" | |
| 39 " %s -U -l LABEL\n" | |
| 40 "Load and unload on-demand Mach services from launchd.\n" | |
| 41 "\n" | |
| 42 " -L, --load load (submit) the job identified by --label;\n" | |
| 43 " COMMAND must be specified\n" | |
| 44 " -U, --unload unload (remove) the job identified by --label\n" | |
| 45 " -l, --label=LABEL identify the job to launchd with LABEL\n" | |
| 46 " -m, --mach-service=SERVICE register SERVICE with the bootstrap server\n" | |
| 47 " --help display this help and exit\n" | |
| 48 " --version output version information and exit\n", | |
| 49 me.c_str(), | |
| 50 me.c_str()); | |
| 51 ToolSupport::UsageTail(me); | |
| 52 } | |
| 53 | |
| 54 int OnDemandServiceToolMain(int argc, char* argv[]) { | |
| 55 const std::string me(basename(argv[0])); | |
| 56 | |
| 57 enum Operation { | |
| 58 kOperationUnknown = 0, | |
| 59 kOperationLoadJob, | |
| 60 kOperationUnloadJob, | |
| 61 }; | |
| 62 | |
| 63 enum OptionFlags { | |
| 64 // “Short” (single-character) options. | |
| 65 kOptionLoadJob = 'L', | |
| 66 kOptionUnloadJob = 'U', | |
| 67 kOptionJobLabel = 'l', | |
| 68 kOptionMachService = 'm', | |
| 69 | |
| 70 // Long options without short equivalents. | |
| 71 kOptionLastChar = 255, | |
| 72 | |
| 73 // Standard options. | |
| 74 kOptionHelp = -2, | |
| 75 kOptionVersion = -3, | |
| 76 }; | |
| 77 | |
| 78 struct { | |
| 79 Operation operation; | |
| 80 std::string job_label; | |
| 81 std::vector<std::string> mach_services; | |
| 82 } options = {}; | |
| 83 | |
| 84 const struct option long_options[] = { | |
| 85 {"load", no_argument, nullptr, kOptionLoadJob}, | |
| 86 {"unload", no_argument, nullptr, kOptionUnloadJob}, | |
| 87 {"label", required_argument, nullptr, kOptionJobLabel}, | |
| 88 {"mach-service", required_argument, nullptr, kOptionMachService}, | |
| 89 {"help", no_argument, nullptr, kOptionHelp}, | |
| 90 {"version", no_argument, nullptr, kOptionVersion}, | |
| 91 {nullptr, 0, nullptr, 0}, | |
| 92 }; | |
| 93 | |
| 94 int opt; | |
| 95 while ((opt = getopt_long(argc, argv, "+LUl:m:", long_options, nullptr)) != | |
| 96 -1) { | |
| 97 switch (opt) { | |
| 98 case kOptionLoadJob: | |
| 99 options.operation = kOperationLoadJob; | |
| 100 break; | |
| 101 case kOptionUnloadJob: | |
| 102 options.operation = kOperationUnloadJob; | |
| 103 break; | |
| 104 case kOptionJobLabel: | |
| 105 options.job_label = optarg; | |
| 106 break; | |
| 107 case kOptionMachService: | |
| 108 options.mach_services.push_back(optarg); | |
| 109 break; | |
| 110 case kOptionHelp: | |
| 111 Usage(me); | |
| 112 return EXIT_SUCCESS; | |
| 113 case kOptionVersion: | |
| 114 ToolSupport::Version(me); | |
| 115 return EXIT_SUCCESS; | |
| 116 default: | |
| 117 ToolSupport::UsageHint(me, nullptr); | |
| 118 return EXIT_FAILURE; | |
| 119 } | |
| 120 } | |
| 121 argc -= optind; | |
| 122 argv += optind; | |
| 123 | |
| 124 if (options.job_label.empty()) { | |
| 125 ToolSupport::UsageHint(me, "must provide -l"); | |
| 126 return EXIT_FAILURE; | |
| 127 } | |
| 128 | |
| 129 switch (options.operation) { | |
| 130 case kOperationLoadJob: { | |
| 131 if (argc == 0) { | |
| 132 ToolSupport::UsageHint(me, "must provide COMMAND with -L"); | |
| 133 return EXIT_FAILURE; | |
| 134 } | |
| 135 | |
| 136 @autoreleasepool { | |
| 137 NSString* job_label = base::SysUTF8ToNSString(options.job_label); | |
| 138 | |
| 139 NSMutableArray* command = [NSMutableArray arrayWithCapacity:argc]; | |
| 140 for (int index = 0; index < argc; ++index) { | |
| 141 NSString* argument = base::SysUTF8ToNSString(argv[index]); | |
| 142 [command addObject:argument]; | |
| 143 } | |
| 144 | |
| 145 NSDictionary* job_dictionary = @{ | |
| 146 @LAUNCH_JOBKEY_LABEL : job_label, | |
| 147 @LAUNCH_JOBKEY_PROGRAMARGUMENTS : command, | |
| 148 }; | |
| 149 | |
| 150 if (!options.mach_services.empty()) { | |
| 151 NSMutableDictionary* mach_services = [NSMutableDictionary | |
| 152 dictionaryWithCapacity:options.mach_services.size()]; | |
| 153 for (std::string mach_service : options.mach_services) { | |
| 154 NSString* mach_service_ns = base::SysUTF8ToNSString(mach_service); | |
| 155 [mach_services setObject:@YES forKey:mach_service_ns]; | |
| 156 } | |
| 157 | |
| 158 NSMutableDictionary* mutable_job_dictionary = | |
| 159 [[job_dictionary mutableCopy] autorelease]; | |
| 160 [mutable_job_dictionary setObject:mach_services | |
| 161 forKey:@LAUNCH_JOBKEY_MACHSERVICES]; | |
| 162 job_dictionary = mutable_job_dictionary; | |
| 163 } | |
| 164 | |
| 165 CFDictionaryRef job_dictionary_cf = | |
| 166 base::mac::NSToCFCast(job_dictionary); | |
| 167 if (!ServiceManagementSubmitJob(job_dictionary_cf)) { | |
| 168 fprintf(stderr, "%s: failed to submit job\n", me.c_str()); | |
| 169 return EXIT_FAILURE; | |
| 170 } | |
| 171 } | |
| 172 | |
| 173 return EXIT_SUCCESS; | |
| 174 } | |
| 175 | |
| 176 case kOperationUnloadJob: { | |
| 177 if (!ServiceManagementRemoveJob(options.job_label, true)) { | |
| 178 fprintf(stderr, "%s: failed to remove job\n", me.c_str()); | |
| 179 return EXIT_FAILURE; | |
| 180 } | |
| 181 | |
| 182 return EXIT_SUCCESS; | |
| 183 } | |
| 184 | |
| 185 default: { | |
| 186 ToolSupport::UsageHint(me, "must provide -L or -U"); | |
| 187 return EXIT_FAILURE; | |
| 188 } | |
| 189 } | |
| 190 } | |
| 191 | |
| 192 } // namespace | |
| 193 } // namespace crashpad | |
| 194 | |
| 195 int main(int argc, char* argv[]) { | |
| 196 return crashpad::OnDemandServiceToolMain(argc, argv); | |
| 197 } | |
| OLD | NEW |