]> git.saurik.com Git - apple/configd.git/blob - scutil.tproj/scutil.c
configd-1109.60.2.tar.gz
[apple/configd.git] / scutil.tproj / scutil.c
1 /*
2 * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
12 *
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
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * June 13, 2005 Allan Nathanson <ajn@apple.com>
28 * - added SCPreferences support
29 *
30 * August 4, 2004 Allan Nathanson <ajn@apple.com>
31 * - added network configuration (prefs) support
32 *
33 * September 25, 2002 Allan Nathanson <ajn@apple.com>
34 * - added command line history & editing
35 *
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
48 #include <TargetConditionals.h>
49 #include <ctype.h>
50 #include <getopt.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <termios.h>
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"
64 #include "commands.h"
65 #include "dictionary.h"
66 #include "net.h"
67 #include "nc.h"
68 #include "prefs.h"
69 #include "session.h"
70 #include "tests.h"
71
72 #define LINE_LENGTH 2048
73
74 __private_extern__ AuthorizationRef authorization = NULL;
75 __private_extern__ InputRef currentInput = NULL;
76 __private_extern__ Boolean doDispatch = FALSE;
77 __private_extern__ int nesting = 0;
78 __private_extern__ SCPreferencesRef ni_prefs = NULL;
79 __private_extern__ CFRunLoopRef notifyRl = NULL;
80 __private_extern__ CFRunLoopSourceRef notifyRls = NULL;
81 __private_extern__ SCPreferencesRef prefs = NULL;
82 __private_extern__ char *prefsPath = NULL;
83 __private_extern__ SCDynamicStoreRef store = NULL;
84 __private_extern__ CFPropertyListRef value = NULL;
85 __private_extern__ CFMutableArrayRef watchedKeys = NULL;
86 __private_extern__ CFMutableArrayRef watchedPatterns = NULL;
87
88 static const struct option longopts[] = {
89 // { "debug", no_argument, NULL, 'd' },
90 // { "dispatch", no_argument, NULL, 'D' },
91 // { "verbose", no_argument, NULL, 'v' },
92 // { "SPI", no_argument, NULL, 'p' },
93 // { "check-reachability", required_argument, NULL, 'r' },
94 // { "timeout", required_argument, NULL, 't' },
95 // { "wait-key", required_argument, NULL, 'w' },
96 // { "watch-reachability", no_argument, NULL, 'W' },
97 { "configuration", no_argument, NULL, 0 },
98 { "dns", no_argument, NULL, 0 },
99 { "get", required_argument, NULL, 0 },
100 { "error", required_argument, NULL, 0 },
101 { "help", no_argument, NULL, '?' },
102 { "nc", required_argument, NULL, 0 },
103 { "net", no_argument, NULL, 0 },
104 { "nwi", no_argument, NULL, 0 },
105 { "prefs", no_argument, NULL, 0 },
106 { "proxy", no_argument, NULL, 0 },
107 { "renew", required_argument, NULL, 0 },
108 { "set", required_argument, NULL, 0 },
109 { "snapshot", no_argument, NULL, 0 },
110 { "user", required_argument, NULL, 0 },
111 { "password", required_argument, NULL, 0 },
112 { "secret", required_argument, NULL, 0 },
113 { "log", required_argument, NULL, 0 },
114 { "advisory", required_argument, NULL, 0 },
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 },
119 { NULL, 0, NULL, 0 }
120 };
121
122
123 __private_extern__
124 CFStringRef
125 _copyStringFromSTDIN(CFStringRef prompt, CFStringRef defaultValue)
126 {
127 char buf[1024];
128 int i;
129 Boolean is_user_prompt = (prompt != NULL && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO));
130 int len;
131 char *modbuf;
132 int modlen;
133 CFStringRef utf8;
134
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 */
145 if (fgets(buf, sizeof(buf), stdin) == NULL) {
146 return NULL;
147 }
148
149 /* Prepare for trim */
150 len = (int)strlen(buf);
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;
164 }
165
166 /* Trim spaces from front */
167 while (modlen > 0 && isspace(modbuf[0])) {
168 modbuf = &modbuf[1];
169 modlen--;
170 }
171
172 /* Trim spaces from back */
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);
183 return utf8;
184 }
185
186 static char *
187 getLine(char *buf, int len, InputRef src)
188 {
189 int n;
190
191 if (src->el) {
192 int count;
193 const char *line;
194
195 line = el_gets(src->el, &count);
196 if (line == NULL)
197 return NULL;
198
199 strlcpy(buf, line, len);
200 } else {
201 if (fgets(buf, len, src->fp) == NULL)
202 return NULL;
203 }
204
205 n = (int)strlen(buf);
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) {
210 /* eat the remainder of the line */
211 do {
212 n = fgetc(src->fp);
213 } while ((n != '\n') && (n != EOF));
214 }
215
216 if (src->h && (buf[0] != '\0')) {
217 HistEvent ev;
218
219 history(src->h, &ev, H_ENTER, buf);
220 }
221
222 return buf;
223 }
224
225
226 static char *
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
277 __private_extern__
278 Boolean
279 process_line(InputRef src)
280 {
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
289 if (getLine(line, sizeof(line), src) == NULL)
290 return FALSE;
291
292 if (nesting > 0) {
293 SCPrint(TRUE, stdout, CFSTR("%d> %s\n"), nesting, line);
294 }
295
296 // break up the input line
297 while ((arg = getString(&s)) != NULL) {
298 if (argc == 0)
299 argv = (char **)malloc(2 * sizeof(char *));
300 else
301 argv = (char **)reallocf(argv, ((argc + 2) * sizeof(char *)));
302 argv[argc++] = arg;
303 }
304
305 if (argc == 0) {
306 return TRUE; // if no arguments
307 }
308
309 /* process the command */
310 if (*argv[0] != '#') {
311 argv[argc] = NULL; // just in case...
312 currentInput = src;
313 do_command(argc, argv);
314 }
315
316 /* free the arguments */
317 for (i = 0; i < argc; i++) {
318 free(argv[i]);
319 }
320 free(argv);
321
322 return !termRequested;
323 }
324
325
326 static void
327 usage(const char *command)
328 {
329 SCPrint(TRUE, stderr, CFSTR("usage: %s\n"), command);
330 SCPrint(TRUE, stderr, CFSTR("\tinteractive access to the dynamic store.\n"));
331 SCPrint(TRUE, stderr, CFSTR("\n"));
332 SCPrint(TRUE, stderr, CFSTR(" or: %s --prefs [preference-file]\n"), command);
333 SCPrint(TRUE, stderr, CFSTR("\tinteractive access to the [raw] stored preferences.\n"));
334 SCPrint(TRUE, stderr, CFSTR("\n"));
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"));
339 SCPrint(TRUE, stderr, CFSTR("\n"));
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"));
344 SCPrint(TRUE, stderr, CFSTR(" or: %s --get pref\n"), command);
345 SCPrint(TRUE, stderr, CFSTR(" or: %s --set pref [newval]\n"), command);
346 SCPrint(TRUE, stderr, CFSTR(" or: %s --get filename path key \n"), command);
347 SCPrint(TRUE, stderr, CFSTR("\tpref\tdisplay (or set) the specified preference. Valid preferences\n"));
348 SCPrint(TRUE, stderr, CFSTR("\t\tinclude:\n"));
349 SCPrint(TRUE, stderr, CFSTR("\t\t\tComputerName, LocalHostName, HostName\n"));
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"));
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"));
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"));
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"));
364
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"));
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"));
373 }
374
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
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
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
391 exit (EX_USAGE);
392 }
393
394
395 static char *
396 prompt(EditLine *el)
397 {
398 #pragma unused(el)
399 #if !TARGET_OS_SIMULATOR
400 return "> ";
401 #else // !TARGET_OS_SIMULATOR
402 return "sim> ";
403 #endif // !TARGET_OS_SIMULATOR
404 }
405
406
407 int
408 main(int argc, char * const argv[])
409 {
410 const char * advisoryInterface = NULL;
411 #if !TARGET_OS_IPHONE
412 Boolean allowNewInterfaces = FALSE;
413 #endif // !TARGET_OS_IPHONE
414 Boolean configuration = FALSE;
415 Boolean disableUntilNeeded = FALSE;
416 Boolean doAdvisory = FALSE;
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;
427 extern int optind;
428 int opt;
429 int opti;
430 const char *prog = argv[0];
431 char *renew = NULL;
432 char *set = NULL;
433 char *nc_cmd = NULL;
434 InputRef src;
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 */
439
440 /* process any arguments */
441
442 while ((opt = getopt_long(argc, argv, "dDvprt:w:W", longopts, &opti)) != -1) {
443 switch(opt) {
444 case 'd':
445 _sc_debug = TRUE;
446 _sc_log = kSCLogDestinationFile; /* enable framework logging */
447 break;
448 case 'D':
449 doDispatch = TRUE;
450 break;
451 case 'v':
452 _sc_verbose = TRUE;
453 _sc_log = kSCLogDestinationFile; /* enable framework logging */
454 break;
455 case 'p':
456 enablePrivateAPI = TRUE;
457 break;
458 case 'r':
459 doReach = TRUE;
460 xStore++;
461 break;
462 case 't':
463 timeout = atoi(optarg);
464 break;
465 case 'w':
466 wait = optarg;
467 xStore++;
468 break;
469 case 'W':
470 watch = TRUE;
471 break;
472 case 0:
473 if (strcmp(longopts[opti].name, "configuration") == 0) {
474 configuration = TRUE;
475 xStore++;
476 } else if (strcmp(longopts[opti].name, "dns") == 0) {
477 doDNS = TRUE;
478 xStore++;
479 } else if (strcmp(longopts[opti].name, "error") == 0) {
480 error = optarg;
481 xStore++;
482 } else if (strcmp(longopts[opti].name, "get") == 0) {
483 get = optarg;
484 xStore++;
485 } else if (strcmp(longopts[opti].name, "nc") == 0) {
486 nc_cmd = optarg;
487 xStore++;
488 } else if (strcmp(longopts[opti].name, "net") == 0) {
489 doNet = TRUE;
490 xStore++;
491 } else if (strcmp(longopts[opti].name, "nwi") == 0) {
492 doNWI = TRUE;
493 xStore++;
494 } else if (strcmp(longopts[opti].name, "prefs") == 0) {
495 doPrefs = TRUE;
496 xStore++;
497 } else if (strcmp(longopts[opti].name, "proxy") == 0) {
498 doProxy = TRUE;
499 xStore++;
500 } else if (strcmp(longopts[opti].name, "renew") == 0) {
501 renew = optarg;
502 xStore++;
503 } else if (strcmp(longopts[opti].name, "set") == 0) {
504 set = optarg;
505 xStore++;
506 } else if (strcmp(longopts[opti].name, "snapshot") == 0) {
507 doSnap = TRUE;
508 xStore++;
509 } else if (strcmp(longopts[opti].name, "log") == 0) {
510 log = optarg;
511 xStore++;
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
517 } else if (strcmp(longopts[opti].name, "disable-until-needed") == 0) {
518 disableUntilNeeded = TRUE;
519 xStore++;
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);
526 } else if (strcmp(longopts[opti].name, "advisory") == 0) {
527 doAdvisory = TRUE;
528 advisoryInterface = optarg;
529 xStore++;
530 }
531 break;
532 case '?':
533 default :
534 usage(prog);
535 }
536 }
537
538 argc -= optind;
539 argv += optind;
540
541 if (xStore > 1) {
542 // if we are attempting to process more than one type of request
543 usage(prog);
544 }
545
546 /* are we asking for a configuration summary */
547 if (configuration) {
548 do_configuration(argc, (char **)argv);
549 /* NOT REACHED */
550 }
551
552 /* are we checking (or watching) the reachability of a host/address */
553 if (doReach) {
554 if (argc < 1) {
555 usage(prog);
556 }
557 if (watch) {
558 do_watchReachability(argc, (char **)argv);
559 } else {
560 do_checkReachability(argc, (char **)argv);
561 }
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
571 /* are we looking up the DNS configuration */
572 if (doDNS) {
573 if (watch) {
574 do_watchDNSConfiguration(argc, (char **)argv);
575 } else {
576 do_showDNSConfiguration(argc, (char **)argv);
577 }
578 /* NOT REACHED */
579 }
580
581 if (doNWI) {
582 if (watch) {
583 do_watchNWI(argc, (char**)argv);
584 } else {
585 do_showNWI(argc, (char**)argv);
586 }
587 /* NOT REACHED */
588 }
589
590 if (doSnap) {
591 if (!enablePrivateAPI) {
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
600 if (doAdvisory) {
601 do_advisory(advisoryInterface, watch, argc, (char**)argv);
602 /* NOT REACHED */
603 }
604
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
616 /* are we looking up a preference value */
617 if (get) {
618 if (argc == 0) {
619 if (findPref(get) < 0) {
620 usage(prog);
621 }
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 */
630 argc++;
631 argv--;
632 } else {
633 usage(prog);
634 }
635
636 do_getPref(get, argc, (char **)argv);
637 /* NOT REACHED */
638 }
639
640 /* are we looking up the proxy configuration */
641 if (doProxy) {
642 do_showProxyConfiguration(argc, (char **)argv);
643 /* NOT REACHED */
644 }
645
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
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 }
663
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
672 /* disableUntilNeeded */
673 if (disableUntilNeeded) {
674 do_disable_until_needed(argc, (char * *)argv);
675 /* NOT REACHED */
676 }
677
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
687 if (doNet) {
688 /* if we are going to be managing the network configuration */
689 commands = (cmdInfo *)commands_net;
690 nCommands = nCommands_net;
691
692 if (!getenv("ENABLE_EXPERIMENTAL_SCUTIL_COMMANDS")) {
693 usage(prog);
694 }
695
696 do_net_init(); /* initialization */
697 do_net_open(argc, (char **)argv); /* open prefs */
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
703 do_dictInit(0, NULL); /* start with an empty dictionary */
704 do_prefs_init(); /* initialization */
705 do_prefs_open(argc, (char **)argv); /* open prefs */
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 }
714
715 /* are we trying to renew a DHCP lease */
716 if (renew != NULL) {
717 do_renew(renew);
718 /* NOT REACHED */
719 }
720
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);
742
743 if (!editmode) {
744 el_set(src->el, EL_EDITMODE, 0);
745 }
746
747 el_set(src->el, EL_EDITOR, "emacs");
748 el_set(src->el, EL_PROMPT, prompt);
749
750 el_source(src->el, NULL);
751
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 }
761
762 while (TRUE) {
763 Boolean ok;
764
765 ok = process_line(src);
766 if (!ok) {
767 break;
768 }
769 }
770
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);
776
777 exit (EX_OK); // insure the process exit status is 0
778 return 0; // ...and make main fit the ANSI spec.
779 }