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) { | |
Robert Sesek
2014/08/20 18:16:07
Keeping this C-style? Or this should be Usage().
| |
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 std::string me(basename(argv[0])); | |
Robert Sesek
2014/08/20 18:16:07
const
| |
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, | |
Robert Sesek
2014/08/20 18:16:07
nit: space before :
| |
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 |