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 |