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