]>
Commit | Line | Data |
---|---|---|
5958d7c0 | 1 | /* |
78deefe8 | 2 | * Copyright (c) 2000-2020 Apple Inc. All rights reserved. |
5958d7c0 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
78403150 | 5 | * |
009ee3c6 A |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
78403150 | 12 | * |
009ee3c6 A |
13 | * The Original Code and all software distributed under the License are |
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
5958d7c0 A |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
009ee3c6 A |
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
18 | * Please see the License for the specific language governing rights and | |
19 | * limitations under the License. | |
78403150 | 20 | * |
5958d7c0 A |
21 | * @APPLE_LICENSE_HEADER_END@ |
22 | */ | |
23 | ||
0fae82ee A |
24 | /* |
25 | * Modification History | |
26 | * | |
edebe297 A |
27 | * June 13, 2005 Allan Nathanson <ajn@apple.com> |
28 | * - added SCPreferences support | |
29 | * | |
dbf6a266 A |
30 | * August 4, 2004 Allan Nathanson <ajn@apple.com> |
31 | * - added network configuration (prefs) support | |
32 | * | |
009ee3c6 A |
33 | * September 25, 2002 Allan Nathanson <ajn@apple.com> |
34 | * - added command line history & editing | |
35 | * | |
0fae82ee A |
36 | * July 9, 2001 Allan Nathanson <ajn@apple.com> |
37 | * - added "-r" option for checking network reachability | |
38 | * - added "-w" option to check/wait for the presence of a | |
39 | * dynamic store key. | |
40 | * | |
41 | * June 1, 2001 Allan Nathanson <ajn@apple.com> | |
42 | * - public API conversion | |
43 | * | |
44 | * November 9, 2000 Allan Nathanson <ajn@apple.com> | |
45 | * - initial revision | |
46 | */ | |
47 | ||
6bb65964 | 48 | #include <TargetConditionals.h> |
5958d7c0 | 49 | #include <ctype.h> |
009ee3c6 | 50 | #include <getopt.h> |
5958d7c0 A |
51 | #include <stdio.h> |
52 | #include <stdlib.h> | |
53 | #include <string.h> | |
009ee3c6 | 54 | #include <termios.h> |
5958d7c0 A |
55 | #include <unistd.h> |
56 | #include <sysexits.h> | |
57 | ||
58 | #ifdef DEBUG | |
59 | #include <mach/mach.h> | |
60 | #include <mach/mach_error.h> | |
61 | #endif /* DEBUG */ | |
62 | ||
63 | #include "scutil.h" | |
5958d7c0 A |
64 | #include "commands.h" |
65 | #include "dictionary.h" | |
dbf6a266 | 66 | #include "net.h" |
6bb65964 | 67 | #include "nc.h" |
009ee3c6 | 68 | #include "prefs.h" |
dbf6a266 A |
69 | #include "session.h" |
70 | #include "tests.h" | |
0fae82ee | 71 | |
78403150 | 72 | #define LINE_LENGTH 2048 |
5958d7c0 | 73 | |
edebe297 | 74 | __private_extern__ AuthorizationRef authorization = NULL; |
dbf6a266 | 75 | __private_extern__ InputRef currentInput = NULL; |
d0784775 | 76 | __private_extern__ Boolean doDispatch = FALSE; |
dbf6a266 | 77 | __private_extern__ int nesting = 0; |
78deefe8 | 78 | __private_extern__ SCPreferencesRef ni_prefs = NULL; |
dbf6a266 A |
79 | __private_extern__ CFRunLoopRef notifyRl = NULL; |
80 | __private_extern__ CFRunLoopSourceRef notifyRls = NULL; | |
81 | __private_extern__ SCPreferencesRef prefs = NULL; | |
78deefe8 | 82 | __private_extern__ char *prefsPath = NULL; |
dbf6a266 A |
83 | __private_extern__ SCDynamicStoreRef store = NULL; |
84 | __private_extern__ CFPropertyListRef value = NULL; | |
85 | __private_extern__ CFMutableArrayRef watchedKeys = NULL; | |
86 | __private_extern__ CFMutableArrayRef watchedPatterns = NULL; | |
009ee3c6 | 87 | |
dbf6a266 | 88 | static const struct option longopts[] = { |
009ee3c6 | 89 | // { "debug", no_argument, NULL, 'd' }, |
d0784775 | 90 | // { "dispatch", no_argument, NULL, 'D' }, |
009ee3c6 A |
91 | // { "verbose", no_argument, NULL, 'v' }, |
92 | // { "SPI", no_argument, NULL, 'p' }, | |
dbf6a266 | 93 | // { "check-reachability", required_argument, NULL, 'r' }, |
009ee3c6 A |
94 | // { "timeout", required_argument, NULL, 't' }, |
95 | // { "wait-key", required_argument, NULL, 'w' }, | |
d0784775 | 96 | // { "watch-reachability", no_argument, NULL, 'W' }, |
260b6351 | 97 | { "configuration", no_argument, NULL, 0 }, |
dbf6a266 | 98 | { "dns", no_argument, NULL, 0 }, |
009ee3c6 | 99 | { "get", required_argument, NULL, 0 }, |
78403150 | 100 | { "error", required_argument, NULL, 0 }, |
009ee3c6 | 101 | { "help", no_argument, NULL, '?' }, |
17d3ee29 | 102 | { "nc", required_argument, NULL, 0 }, |
dbf6a266 | 103 | { "net", no_argument, NULL, 0 }, |
17d3ee29 | 104 | { "nwi", no_argument, NULL, 0 }, |
edebe297 | 105 | { "prefs", no_argument, NULL, 0 }, |
dbf6a266 | 106 | { "proxy", no_argument, NULL, 0 }, |
5e9ce69e | 107 | { "renew", required_argument, NULL, 0 }, |
009ee3c6 | 108 | { "set", required_argument, NULL, 0 }, |
17d3ee29 A |
109 | { "snapshot", no_argument, NULL, 0 }, |
110 | { "user", required_argument, NULL, 0 }, | |
111 | { "password", required_argument, NULL, 0 }, | |
112 | { "secret", required_argument, NULL, 0 }, | |
5e9ce69e | 113 | { "log", required_argument, NULL, 0 }, |
f715d946 | 114 | { "advisory", required_argument, NULL, 0 }, |
43bfd57e A |
115 | #if !TARGET_OS_IPHONE |
116 | { "allow-new-interfaces", no_argument, NULL, 0 }, | |
117 | #endif // !TARGET_OS_IPHONE | |
118 | { "disable-until-needed", no_argument, NULL, 0 }, | |
dbf6a266 | 119 | { NULL, 0, NULL, 0 } |
009ee3c6 | 120 | }; |
5958d7c0 A |
121 | |
122 | ||
6bb65964 A |
123 | __private_extern__ |
124 | CFStringRef | |
5e9ce69e | 125 | _copyStringFromSTDIN(CFStringRef prompt, CFStringRef defaultValue) |
6bb65964 A |
126 | { |
127 | char buf[1024]; | |
5e9ce69e A |
128 | int i; |
129 | Boolean is_user_prompt = (prompt != NULL && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)); | |
78403150 | 130 | int len; |
5e9ce69e | 131 | char *modbuf; |
78403150 | 132 | int modlen; |
6bb65964 A |
133 | CFStringRef utf8; |
134 | ||
5e9ce69e A |
135 | /* Print out a prompt to user that entry is desired */ |
136 | if (is_user_prompt) { | |
137 | if (defaultValue != NULL) { | |
138 | SCPrint(TRUE, stdout, CFSTR("%@ [%@]: "), prompt, defaultValue); | |
139 | } else { | |
140 | SCPrint(TRUE, stdout, CFSTR("%@: "), prompt); | |
141 | } | |
142 | } | |
143 | ||
144 | /* Get user input */ | |
6bb65964 A |
145 | if (fgets(buf, sizeof(buf), stdin) == NULL) { |
146 | return NULL; | |
147 | } | |
148 | ||
5e9ce69e | 149 | /* Prepare for trim */ |
78403150 | 150 | len = (int)strlen(buf); |
5e9ce69e A |
151 | modbuf = buf; |
152 | modlen = len; | |
153 | ||
154 | /* Trim new-line */ | |
155 | if ((modlen > 0) && (modbuf[modlen - 1] == '\n')) { | |
156 | modbuf[modlen - 1] = '\0'; | |
157 | modlen--; | |
158 | } | |
159 | ||
160 | /* If nothing was entered at the user prompt, set default */ | |
161 | if (is_user_prompt && defaultValue != NULL && modlen == 0) { | |
162 | CFRetain(defaultValue); | |
163 | return defaultValue; | |
6bb65964 A |
164 | } |
165 | ||
5e9ce69e A |
166 | /* Trim spaces from front */ |
167 | while (modlen > 0 && isspace(modbuf[0])) { | |
168 | modbuf = &modbuf[1]; | |
169 | modlen--; | |
170 | } | |
171 | ||
78403150 | 172 | /* Trim spaces from back */ |
5e9ce69e A |
173 | for (i = modlen - 1; i >= 0; i--) { |
174 | if (isspace(buf[i])) { | |
175 | buf[i] = '\0'; | |
176 | modlen--; | |
177 | } else { | |
178 | break; | |
179 | } | |
180 | } | |
181 | ||
182 | utf8 = CFStringCreateWithBytes(NULL, (UInt8 *)modbuf, modlen, kCFStringEncodingUTF8, TRUE); | |
6bb65964 A |
183 | return utf8; |
184 | } | |
185 | ||
5958d7c0 | 186 | static char * |
009ee3c6 | 187 | getLine(char *buf, int len, InputRef src) |
5958d7c0 | 188 | { |
009ee3c6 | 189 | int n; |
5958d7c0 | 190 | |
009ee3c6 A |
191 | if (src->el) { |
192 | int count; | |
193 | const char *line; | |
5958d7c0 | 194 | |
009ee3c6 A |
195 | line = el_gets(src->el, &count); |
196 | if (line == NULL) | |
197 | return NULL; | |
198 | ||
942cecd7 | 199 | strlcpy(buf, line, len); |
5958d7c0 | 200 | } else { |
009ee3c6 A |
201 | if (fgets(buf, len, src->fp) == NULL) |
202 | return NULL; | |
203 | } | |
204 | ||
78403150 | 205 | n = (int)strlen(buf); |
009ee3c6 A |
206 | if (buf[n-1] == '\n') { |
207 | /* the entire line fit in the buffer, remove the newline */ | |
208 | buf[n-1] = '\0'; | |
209 | } else if (!src->el) { | |
5958d7c0 A |
210 | /* eat the remainder of the line */ |
211 | do { | |
009ee3c6 A |
212 | n = fgetc(src->fp); |
213 | } while ((n != '\n') && (n != EOF)); | |
214 | } | |
215 | ||
6bb65964 | 216 | if (src->h && (buf[0] != '\0')) { |
009ee3c6 A |
217 | HistEvent ev; |
218 | ||
219 | history(src->h, &ev, H_ENTER, buf); | |
5958d7c0 A |
220 | } |
221 | ||
222 | return buf; | |
223 | } | |
224 | ||
225 | ||
dbf6a266 | 226 | static char * |
5958d7c0 A |
227 | getString(char **line) |
228 | { | |
229 | char *s, *e, c, *string; | |
230 | int i, isQuoted = 0, escaped = 0; | |
231 | ||
232 | if (*line == NULL) return NULL; | |
233 | if (**line == '\0') return NULL; | |
234 | ||
235 | /* Skip leading white space */ | |
236 | while (isspace(**line)) *line += 1; | |
237 | ||
238 | /* Grab the next string */ | |
239 | s = *line; | |
240 | if (*s == '\0') { | |
241 | return NULL; /* no string available */ | |
242 | } else if (*s == '"') { | |
243 | isQuoted = 1; /* it's a quoted string */ | |
244 | s++; | |
245 | } | |
246 | ||
247 | for (e = s; (c = *e) != '\0'; e++) { | |
248 | if (isQuoted && (c == '"')) | |
249 | break; /* end of quoted string */ | |
250 | if (c == '\\') { | |
251 | e++; | |
252 | if (*e == '\0') | |
253 | break; /* if premature end-of-string */ | |
254 | if ((*e == '"') || isspace(*e)) | |
255 | escaped++; /* if escaped quote or white space */ | |
256 | } | |
257 | if (!isQuoted && isspace(c)) | |
258 | break; /* end of non-quoted string */ | |
259 | } | |
260 | ||
261 | string = malloc(e - s - escaped + 1); | |
262 | ||
263 | for (i = 0; s < e; s++) { | |
264 | string[i] = *s; | |
265 | if (!((s[0] == '\\') && ((s[1] == '"') || isspace(s[1])))) i++; | |
266 | } | |
267 | string[i] = '\0'; | |
268 | ||
269 | if (isQuoted) | |
270 | e++; /* move past end of quoted string */ | |
271 | ||
272 | *line = e; | |
273 | return string; | |
274 | } | |
275 | ||
276 | ||
dbf6a266 | 277 | __private_extern__ |
0fae82ee | 278 | Boolean |
009ee3c6 | 279 | process_line(InputRef src) |
5958d7c0 | 280 | { |
dbf6a266 A |
281 | char *arg; |
282 | int argc = 0; | |
283 | char **argv = NULL; | |
284 | int i; | |
285 | char line[LINE_LENGTH]; | |
286 | char *s = line; | |
287 | ||
288 | // if end-of-file, exit | |
009ee3c6 | 289 | if (getLine(line, sizeof(line), src) == NULL) |
5958d7c0 A |
290 | return FALSE; |
291 | ||
0fae82ee | 292 | if (nesting > 0) { |
a5f60add | 293 | SCPrint(TRUE, stdout, CFSTR("%d> %s\n"), nesting, line); |
5958d7c0 A |
294 | } |
295 | ||
dbf6a266 | 296 | // break up the input line |
5958d7c0 A |
297 | while ((arg = getString(&s)) != NULL) { |
298 | if (argc == 0) | |
299 | argv = (char **)malloc(2 * sizeof(char *)); | |
300 | else | |
dbf6a266 | 301 | argv = (char **)reallocf(argv, ((argc + 2) * sizeof(char *))); |
5958d7c0 A |
302 | argv[argc++] = arg; |
303 | } | |
304 | ||
dbf6a266 A |
305 | if (argc == 0) { |
306 | return TRUE; // if no arguments | |
307 | } | |
5958d7c0 | 308 | |
dbf6a266 A |
309 | /* process the command */ |
310 | if (*argv[0] != '#') { | |
311 | argv[argc] = NULL; // just in case... | |
312 | currentInput = src; | |
313 | do_command(argc, argv); | |
314 | } | |
5958d7c0 | 315 | |
dbf6a266 A |
316 | /* free the arguments */ |
317 | for (i = 0; i < argc; i++) { | |
318 | free(argv[i]); | |
5958d7c0 | 319 | } |
dbf6a266 | 320 | free(argv); |
5958d7c0 | 321 | |
dbf6a266 | 322 | return !termRequested; |
5958d7c0 A |
323 | } |
324 | ||
325 | ||
dbf6a266 | 326 | static void |
0fae82ee A |
327 | usage(const char *command) |
328 | { | |
329 | SCPrint(TRUE, stderr, CFSTR("usage: %s\n"), command); | |
009ee3c6 A |
330 | SCPrint(TRUE, stderr, CFSTR("\tinteractive access to the dynamic store.\n")); |
331 | SCPrint(TRUE, stderr, CFSTR("\n")); | |
6bb65964 | 332 | SCPrint(TRUE, stderr, CFSTR(" or: %s --prefs [preference-file]\n"), command); |
edebe297 A |
333 | SCPrint(TRUE, stderr, CFSTR("\tinteractive access to the [raw] stored preferences.\n")); |
334 | SCPrint(TRUE, stderr, CFSTR("\n")); | |
a40a14f8 A |
335 | SCPrint(TRUE, stderr, CFSTR(" or: %s [-W] -r nodename\n"), command); |
336 | SCPrint(TRUE, stderr, CFSTR(" or: %s [-W] -r address\n"), command); | |
337 | SCPrint(TRUE, stderr, CFSTR(" or: %s [-W] -r local-address remote-address\n"), command); | |
338 | SCPrint(TRUE, stderr, CFSTR("\tcheck reachability of node, address, or address pair (-W to \"watch\").\n")); | |
009ee3c6 | 339 | SCPrint(TRUE, stderr, CFSTR("\n")); |
0fae82ee A |
340 | SCPrint(TRUE, stderr, CFSTR(" or: %s -w dynamic-store-key [ -t timeout ]\n"), command); |
341 | SCPrint(TRUE, stderr, CFSTR("\t-w\twait for presense of dynamic store key\n")); | |
342 | SCPrint(TRUE, stderr, CFSTR("\t-t\ttime to wait for key\n")); | |
343 | SCPrint(TRUE, stderr, CFSTR("\n")); | |
009ee3c6 A |
344 | SCPrint(TRUE, stderr, CFSTR(" or: %s --get pref\n"), command); |
345 | SCPrint(TRUE, stderr, CFSTR(" or: %s --set pref [newval]\n"), command); | |
5e9ce69e | 346 | SCPrint(TRUE, stderr, CFSTR(" or: %s --get filename path key \n"), command); |
009ee3c6 A |
347 | SCPrint(TRUE, stderr, CFSTR("\tpref\tdisplay (or set) the specified preference. Valid preferences\n")); |
348 | SCPrint(TRUE, stderr, CFSTR("\t\tinclude:\n")); | |
edebe297 | 349 | SCPrint(TRUE, stderr, CFSTR("\t\t\tComputerName, LocalHostName, HostName\n")); |
009ee3c6 A |
350 | SCPrint(TRUE, stderr, CFSTR("\tnewval\tNew preference value to be set. If not specified,\n")); |
351 | SCPrint(TRUE, stderr, CFSTR("\t\tthe new value will be read from standard input.\n")); | |
dbf6a266 A |
352 | SCPrint(TRUE, stderr, CFSTR("\n")); |
353 | SCPrint(TRUE, stderr, CFSTR(" or: %s --dns\n"), command); | |
354 | SCPrint(TRUE, stderr, CFSTR("\tshow DNS configuration.\n")); | |
355 | SCPrint(TRUE, stderr, CFSTR("\n")); | |
356 | SCPrint(TRUE, stderr, CFSTR(" or: %s --proxy\n"), command); | |
357 | SCPrint(TRUE, stderr, CFSTR("\tshow \"proxy\" configuration.\n")); | |
17d3ee29 A |
358 | SCPrint(TRUE, stderr, CFSTR("\n")); |
359 | SCPrint(TRUE, stderr, CFSTR(" or: %s --nwi\n"), command); | |
360 | SCPrint(TRUE, stderr, CFSTR("\tshow network information\n")); | |
5e9ce69e A |
361 | SCPrint(TRUE, stderr, CFSTR("\n")); |
362 | SCPrint(TRUE, stderr, CFSTR(" or: %s --nc\n"), command); | |
363 | SCPrint(TRUE, stderr, CFSTR("\tshow VPN network configuration information. Use --nc help for full command list\n")); | |
dbf6a266 | 364 | |
78403150 A |
365 | if (_sc_debug) { |
366 | SCPrint(TRUE, stderr, CFSTR("\n")); | |
367 | SCPrint(TRUE, stderr, CFSTR(" or: %s --log IPMonitor [off|on]\n"), command); | |
368 | SCPrint(TRUE, stderr, CFSTR("\tmanage logging.\n")); | |
942cecd7 A |
369 | |
370 | SCPrint(TRUE, stderr, CFSTR("\n")); | |
371 | SCPrint(TRUE, stderr, CFSTR(" or: %s --disable-until-needed <interfaceName> [on|off ]\n"), command); | |
372 | SCPrint(TRUE, stderr, CFSTR("\tmanage secondary interface demand.\n")); | |
78403150 A |
373 | } |
374 | ||
43bfd57e A |
375 | #if !TARGET_OS_IPHONE |
376 | SCPrint(TRUE, stderr, CFSTR("\n")); | |
377 | SCPrint(TRUE, stderr, CFSTR(" or: %s --allow-new-interfaces [off|on]\n"), command); | |
378 | SCPrint(TRUE, stderr, CFSTR("\tmanage new interface creation with screen locked.\n")); | |
379 | #endif // !TARGET_OS_IPHONE | |
380 | ||
dbf6a266 A |
381 | if (getenv("ENABLE_EXPERIMENTAL_SCUTIL_COMMANDS")) { |
382 | SCPrint(TRUE, stderr, CFSTR("\n")); | |
383 | SCPrint(TRUE, stderr, CFSTR(" or: %s --net\n"), command); | |
384 | SCPrint(TRUE, stderr, CFSTR("\tmanage network configuration.\n")); | |
385 | } | |
386 | ||
78403150 A |
387 | SCPrint(TRUE, stderr, CFSTR("\n")); |
388 | SCPrint(TRUE, stderr, CFSTR(" or: %s --error err#\n"), command); | |
389 | SCPrint(TRUE, stderr, CFSTR("\tdisplay a descriptive message for the given error code\n")); | |
390 | ||
0fae82ee A |
391 | exit (EX_USAGE); |
392 | } | |
393 | ||
394 | ||
009ee3c6 A |
395 | static char * |
396 | prompt(EditLine *el) | |
397 | { | |
1ef45fa4 | 398 | #pragma unused(el) |
942cecd7 | 399 | #if !TARGET_OS_SIMULATOR |
009ee3c6 | 400 | return "> "; |
942cecd7 | 401 | #else // !TARGET_OS_SIMULATOR |
5e9ce69e | 402 | return "sim> "; |
942cecd7 | 403 | #endif // !TARGET_OS_SIMULATOR |
009ee3c6 A |
404 | } |
405 | ||
406 | ||
5958d7c0 | 407 | int |
a5f60add | 408 | main(int argc, char * const argv[]) |
5958d7c0 | 409 | { |
260b6351 | 410 | const char * advisoryInterface = NULL; |
43bfd57e A |
411 | #if !TARGET_OS_IPHONE |
412 | Boolean allowNewInterfaces = FALSE; | |
413 | #endif // !TARGET_OS_IPHONE | |
260b6351 | 414 | Boolean configuration = FALSE; |
43bfd57e | 415 | Boolean disableUntilNeeded = FALSE; |
f715d946 | 416 | Boolean doAdvisory = FALSE; |
43bfd57e A |
417 | Boolean doDNS = FALSE; |
418 | Boolean doNet = FALSE; | |
419 | Boolean doNWI = FALSE; | |
420 | Boolean doPrefs = FALSE; | |
421 | Boolean doProxy = FALSE; | |
422 | Boolean doReach = FALSE; | |
423 | Boolean doSnap = FALSE; | |
424 | char *error = NULL; | |
425 | char *get = NULL; | |
426 | char *log = NULL; | |
0fae82ee A |
427 | extern int optind; |
428 | int opt; | |
009ee3c6 | 429 | int opti; |
43bfd57e A |
430 | const char *prog = argv[0]; |
431 | char *renew = NULL; | |
432 | char *set = NULL; | |
433 | char *nc_cmd = NULL; | |
009ee3c6 | 434 | InputRef src; |
43bfd57e A |
435 | int timeout = 15; /* default timeout (in seconds) */ |
436 | char *wait = NULL; | |
437 | Boolean watch = FALSE; | |
438 | int xStore = 0; /* non dynamic store command line options */ | |
5958d7c0 A |
439 | |
440 | /* process any arguments */ | |
441 | ||
1ef45fa4 | 442 | while ((opt = getopt_long(argc, argv, "dDvprt:w:W", longopts, &opti)) != -1) { |
5958d7c0 A |
443 | switch(opt) { |
444 | case 'd': | |
0fae82ee | 445 | _sc_debug = TRUE; |
59647b27 | 446 | _sc_log = kSCLogDestinationFile; /* enable framework logging */ |
5958d7c0 | 447 | break; |
d0784775 A |
448 | case 'D': |
449 | doDispatch = TRUE; | |
450 | break; | |
5958d7c0 | 451 | case 'v': |
0fae82ee | 452 | _sc_verbose = TRUE; |
59647b27 | 453 | _sc_log = kSCLogDestinationFile; /* enable framework logging */ |
0fae82ee A |
454 | break; |
455 | case 'p': | |
456 | enablePrivateAPI = TRUE; | |
5958d7c0 A |
457 | break; |
458 | case 'r': | |
edebe297 | 459 | doReach = TRUE; |
009ee3c6 | 460 | xStore++; |
0fae82ee A |
461 | break; |
462 | case 't': | |
463 | timeout = atoi(optarg); | |
464 | break; | |
465 | case 'w': | |
466 | wait = optarg; | |
009ee3c6 A |
467 | xStore++; |
468 | break; | |
a40a14f8 A |
469 | case 'W': |
470 | watch = TRUE; | |
471 | break; | |
009ee3c6 | 472 | case 0: |
260b6351 A |
473 | if (strcmp(longopts[opti].name, "configuration") == 0) { |
474 | configuration = TRUE; | |
475 | xStore++; | |
476 | } else if (strcmp(longopts[opti].name, "dns") == 0) { | |
edebe297 | 477 | doDNS = TRUE; |
dbf6a266 | 478 | xStore++; |
78403150 A |
479 | } else if (strcmp(longopts[opti].name, "error") == 0) { |
480 | error = optarg; | |
481 | xStore++; | |
dbf6a266 | 482 | } else if (strcmp(longopts[opti].name, "get") == 0) { |
009ee3c6 A |
483 | get = optarg; |
484 | xStore++; | |
17d3ee29 A |
485 | } else if (strcmp(longopts[opti].name, "nc") == 0) { |
486 | nc_cmd = optarg; | |
487 | xStore++; | |
dbf6a266 | 488 | } else if (strcmp(longopts[opti].name, "net") == 0) { |
edebe297 A |
489 | doNet = TRUE; |
490 | xStore++; | |
17d3ee29 A |
491 | } else if (strcmp(longopts[opti].name, "nwi") == 0) { |
492 | doNWI = TRUE; | |
493 | xStore++; | |
edebe297 A |
494 | } else if (strcmp(longopts[opti].name, "prefs") == 0) { |
495 | doPrefs = TRUE; | |
dbf6a266 A |
496 | xStore++; |
497 | } else if (strcmp(longopts[opti].name, "proxy") == 0) { | |
edebe297 | 498 | doProxy = TRUE; |
dbf6a266 | 499 | xStore++; |
5e9ce69e A |
500 | } else if (strcmp(longopts[opti].name, "renew") == 0) { |
501 | renew = optarg; | |
502 | xStore++; | |
009ee3c6 A |
503 | } else if (strcmp(longopts[opti].name, "set") == 0) { |
504 | set = optarg; | |
505 | xStore++; | |
17d3ee29 A |
506 | } else if (strcmp(longopts[opti].name, "snapshot") == 0) { |
507 | doSnap = TRUE; | |
6bb65964 | 508 | xStore++; |
5e9ce69e A |
509 | } else if (strcmp(longopts[opti].name, "log") == 0) { |
510 | log = optarg; | |
511 | xStore++; | |
43bfd57e A |
512 | #if !TARGET_OS_IPHONE |
513 | } else if (strcmp(longopts[opti].name, "allow-new-interfaces") == 0) { | |
514 | allowNewInterfaces = TRUE; | |
515 | xStore++; | |
516 | #endif // !TARGET_OS_IPHONE | |
9de8ab86 A |
517 | } else if (strcmp(longopts[opti].name, "disable-until-needed") == 0) { |
518 | disableUntilNeeded = TRUE; | |
519 | xStore++; | |
17d3ee29 A |
520 | } else if (strcmp(longopts[opti].name, "user") == 0) { |
521 | username = CFStringCreateWithCString(NULL, optarg, kCFStringEncodingUTF8); | |
522 | } else if (strcmp(longopts[opti].name, "password") == 0) { | |
523 | password = CFStringCreateWithCString(NULL, optarg, kCFStringEncodingUTF8); | |
524 | } else if (strcmp(longopts[opti].name, "secret") == 0) { | |
525 | sharedsecret = CFStringCreateWithCString(NULL, optarg, kCFStringEncodingUTF8); | |
f715d946 A |
526 | } else if (strcmp(longopts[opti].name, "advisory") == 0) { |
527 | doAdvisory = TRUE; | |
528 | advisoryInterface = optarg; | |
529 | xStore++; | |
009ee3c6 | 530 | } |
5958d7c0 A |
531 | break; |
532 | case '?': | |
533 | default : | |
0fae82ee | 534 | usage(prog); |
a5f60add | 535 | } |
1ef45fa4 A |
536 | } |
537 | ||
5958d7c0 A |
538 | argc -= optind; |
539 | argv += optind; | |
540 | ||
009ee3c6 A |
541 | if (xStore > 1) { |
542 | // if we are attempting to process more than one type of request | |
0fae82ee A |
543 | usage(prog); |
544 | } | |
5e9ce69e | 545 | |
260b6351 A |
546 | /* are we asking for a configuration summary */ |
547 | if (configuration) { | |
548 | do_configuration(argc, (char **)argv); | |
549 | /* NOT REACHED */ | |
550 | } | |
551 | ||
a40a14f8 | 552 | /* are we checking (or watching) the reachability of a host/address */ |
edebe297 | 553 | if (doReach) { |
a40a14f8 | 554 | if (argc < 1) { |
009ee3c6 A |
555 | usage(prog); |
556 | } | |
a40a14f8 A |
557 | if (watch) { |
558 | do_watchReachability(argc, (char **)argv); | |
559 | } else { | |
560 | do_checkReachability(argc, (char **)argv); | |
561 | } | |
0fae82ee A |
562 | /* NOT REACHED */ |
563 | } | |
564 | ||
565 | /* are we waiting on the presense of a dynamic store key */ | |
566 | if (wait) { | |
567 | do_wait(wait, timeout); | |
568 | /* NOT REACHED */ | |
569 | } | |
570 | ||
dbf6a266 | 571 | /* are we looking up the DNS configuration */ |
edebe297 | 572 | if (doDNS) { |
78403150 A |
573 | if (watch) { |
574 | do_watchDNSConfiguration(argc, (char **)argv); | |
575 | } else { | |
576 | do_showDNSConfiguration(argc, (char **)argv); | |
577 | } | |
dbf6a266 A |
578 | /* NOT REACHED */ |
579 | } | |
580 | ||
17d3ee29 | 581 | if (doNWI) { |
78403150 A |
582 | if (watch) { |
583 | do_watchNWI(argc, (char**)argv); | |
584 | } else { | |
585 | do_showNWI(argc, (char**)argv); | |
586 | } | |
17d3ee29 A |
587 | /* NOT REACHED */ |
588 | } | |
589 | ||
590 | if (doSnap) { | |
1ef45fa4 | 591 | if (!enablePrivateAPI) { |
17d3ee29 A |
592 | usage(prog); |
593 | } | |
594 | ||
595 | do_open(0, NULL); /* open the dynamic store */ | |
596 | do_snapshot(argc, (char**)argv); | |
597 | exit(0); | |
598 | } | |
599 | ||
f715d946 A |
600 | if (doAdvisory) { |
601 | do_advisory(advisoryInterface, watch, argc, (char**)argv); | |
602 | /* NOT REACHED */ | |
603 | } | |
604 | ||
78403150 A |
605 | /* are we translating error #'s to descriptive text */ |
606 | if (error != NULL) { | |
607 | int sc_status = atoi(error); | |
608 | ||
609 | SCPrint(TRUE, stdout, CFSTR("Error: 0x%08x %d %s\n"), | |
610 | sc_status, | |
611 | sc_status, | |
612 | SCErrorString(sc_status)); | |
613 | exit(0); | |
614 | } | |
615 | ||
009ee3c6 A |
616 | /* are we looking up a preference value */ |
617 | if (get) { | |
942cecd7 | 618 | if (argc == 0) { |
5e9ce69e A |
619 | if (findPref(get) < 0) { |
620 | usage(prog); | |
621 | } | |
942cecd7 A |
622 | } else if (argc == 2) { |
623 | /* | |
624 | * extended --get | |
625 | * i.e. scutil --get <filename> <prefs path> <key> | |
626 | * | |
627 | * need to go back one argument to re-use the 1st "--get" | |
628 | * argument as the prefs path name | |
629 | */ | |
5e9ce69e A |
630 | argc++; |
631 | argv--; | |
942cecd7 A |
632 | } else { |
633 | usage(prog); | |
009ee3c6 | 634 | } |
5e9ce69e | 635 | |
009ee3c6 A |
636 | do_getPref(get, argc, (char **)argv); |
637 | /* NOT REACHED */ | |
638 | } | |
639 | ||
dbf6a266 | 640 | /* are we looking up the proxy configuration */ |
edebe297 | 641 | if (doProxy) { |
dbf6a266 A |
642 | do_showProxyConfiguration(argc, (char **)argv); |
643 | /* NOT REACHED */ | |
644 | } | |
645 | ||
009ee3c6 A |
646 | /* are we changing a preference value */ |
647 | if (set) { | |
648 | if (findPref(set) < 0) { | |
649 | usage(prog); | |
650 | } | |
651 | do_setPref(set, argc, (char **)argv); | |
652 | /* NOT REACHED */ | |
653 | } | |
654 | ||
5e9ce69e A |
655 | /* verbose log */ |
656 | if (log != NULL) { | |
657 | if (strcasecmp(log, "IPMonitor")) { | |
658 | usage(prog); | |
659 | } | |
660 | do_log(log, argc, (char * *)argv); | |
661 | /* NOT REACHED */ | |
662 | } | |
78403150 | 663 | |
43bfd57e A |
664 | #if !TARGET_OS_IPHONE |
665 | /* allowNewInterfaces */ | |
666 | if (allowNewInterfaces) { | |
667 | do_ifnamer("allow-new-interfaces", argc, (char * *)argv); | |
668 | /* NOT REACHED */ | |
669 | } | |
670 | #endif // !TARGET_OS_IPHONE | |
671 | ||
9de8ab86 A |
672 | /* disableUntilNeeded */ |
673 | if (disableUntilNeeded) { | |
674 | do_disable_until_needed(argc, (char * *)argv); | |
675 | /* NOT REACHED */ | |
676 | } | |
43bfd57e | 677 | |
6bb65964 A |
678 | /* network connection commands */ |
679 | if (nc_cmd) { | |
680 | if (find_nc_cmd(nc_cmd) < 0) { | |
681 | usage(prog); | |
682 | } | |
683 | do_nc_cmd(nc_cmd, argc, (char **)argv, watch); | |
684 | /* NOT REACHED */ | |
685 | } | |
686 | ||
edebe297 | 687 | if (doNet) { |
dbf6a266 | 688 | /* if we are going to be managing the network configuration */ |
edebe297 A |
689 | commands = (cmdInfo *)commands_net; |
690 | nCommands = nCommands_net; | |
dbf6a266 A |
691 | |
692 | if (!getenv("ENABLE_EXPERIMENTAL_SCUTIL_COMMANDS")) { | |
693 | usage(prog); | |
694 | } | |
695 | ||
5e9ce69e A |
696 | do_net_init(); /* initialization */ |
697 | do_net_open(argc, (char **)argv); /* open prefs */ | |
edebe297 A |
698 | } else if (doPrefs) { |
699 | /* if we are going to be managing the network configuration */ | |
700 | commands = (cmdInfo *)commands_prefs; | |
701 | nCommands = nCommands_prefs; | |
702 | ||
5e9ce69e A |
703 | do_dictInit(0, NULL); /* start with an empty dictionary */ |
704 | do_prefs_init(); /* initialization */ | |
6bb65964 | 705 | do_prefs_open(argc, (char **)argv); /* open prefs */ |
dbf6a266 A |
706 | } else { |
707 | /* if we are going to be managing the dynamic store */ | |
708 | commands = (cmdInfo *)commands_store; | |
709 | nCommands = nCommands_store; | |
710 | ||
711 | do_dictInit(0, NULL); /* start with an empty dictionary */ | |
712 | do_open(0, NULL); /* open the dynamic store */ | |
713 | } | |
5958d7c0 | 714 | |
5e9ce69e A |
715 | /* are we trying to renew a DHCP lease */ |
716 | if (renew != NULL) { | |
717 | do_renew(renew); | |
718 | /* NOT REACHED */ | |
719 | } | |
720 | ||
009ee3c6 A |
721 | /* allocate command input stream */ |
722 | src = (InputRef)CFAllocatorAllocate(NULL, sizeof(Input), 0); | |
723 | src->fp = stdin; | |
724 | src->el = NULL; | |
725 | src->h = NULL; | |
726 | ||
727 | if (isatty(fileno(src->fp))) { | |
728 | int editmode = 1; | |
729 | HistEvent ev; | |
730 | struct termios t; | |
731 | ||
732 | if (tcgetattr(fileno(src->fp), &t) != -1) { | |
733 | if ((t.c_lflag & ECHO) == 0) { | |
734 | editmode = 0; | |
735 | } | |
736 | } | |
737 | src->el = el_init(prog, src->fp, stdout, stderr); | |
738 | src->h = history_init(); | |
739 | ||
740 | (void)history(src->h, &ev, H_SETSIZE, INT_MAX); | |
741 | el_set(src->el, EL_HIST, history, src->h); | |
5958d7c0 | 742 | |
009ee3c6 A |
743 | if (!editmode) { |
744 | el_set(src->el, EL_EDITMODE, 0); | |
745 | } | |
5958d7c0 | 746 | |
009ee3c6 A |
747 | el_set(src->el, EL_EDITOR, "emacs"); |
748 | el_set(src->el, EL_PROMPT, prompt); | |
5958d7c0 | 749 | |
009ee3c6 | 750 | el_source(src->el, NULL); |
5958d7c0 | 751 | |
009ee3c6 A |
752 | if ((el_get(src->el, EL_EDITMODE, &editmode) != -1) && editmode != 0) { |
753 | el_set(src->el, EL_SIGNAL, 1); | |
754 | } else { | |
755 | history_end(src->h); | |
756 | src->h = NULL; | |
757 | el_end(src->el); | |
758 | src->el = NULL; | |
759 | } | |
760 | } | |
5958d7c0 | 761 | |
a40a14f8 A |
762 | while (TRUE) { |
763 | Boolean ok; | |
764 | ||
765 | ok = process_line(src); | |
766 | if (!ok) { | |
767 | break; | |
768 | } | |
5958d7c0 A |
769 | } |
770 | ||
009ee3c6 A |
771 | /* close the socket, free resources */ |
772 | if (src->h) history_end(src->h); | |
773 | if (src->el) el_end(src->el); | |
774 | (void)fclose(src->fp); | |
775 | CFAllocatorDeallocate(NULL, src); | |
5958d7c0 A |
776 | |
777 | exit (EX_OK); // insure the process exit status is 0 | |
778 | return 0; // ...and make main fit the ANSI spec. | |
779 | } |