]> git.saurik.com Git - apple/configd.git/blob - scutil.tproj/scutil.c
configd-1061.141.1.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 { "dns", no_argument, NULL, 0 },
98 { "get", required_argument, NULL, 0 },
99 { "error", required_argument, NULL, 0 },
100 { "help", no_argument, NULL, '?' },
101 { "nc", required_argument, NULL, 0 },
102 { "net", no_argument, NULL, 0 },
103 { "nwi", no_argument, NULL, 0 },
104 { "prefs", no_argument, NULL, 0 },
105 { "proxy", no_argument, NULL, 0 },
106 { "renew", required_argument, NULL, 0 },
107 { "set", required_argument, NULL, 0 },
108 { "snapshot", no_argument, NULL, 0 },
109 { "user", required_argument, NULL, 0 },
110 { "password", required_argument, NULL, 0 },
111 { "secret", required_argument, NULL, 0 },
112 { "log", required_argument, NULL, 0 },
113 { "advisory", required_argument, NULL, 0 },
114 #if !TARGET_OS_IPHONE
115 { "allow-new-interfaces", no_argument, NULL, 0 },
116 #endif // !TARGET_OS_IPHONE
117 { "disable-until-needed", no_argument, NULL, 0 },
118 { NULL, 0, NULL, 0 }
119 };
120
121
122 __private_extern__
123 CFStringRef
124 _copyStringFromSTDIN(CFStringRef prompt, CFStringRef defaultValue)
125 {
126 char buf[1024];
127 int i;
128 Boolean is_user_prompt = (prompt != NULL && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO));
129 int len;
130 char *modbuf;
131 int modlen;
132 CFStringRef utf8;
133
134 /* Print out a prompt to user that entry is desired */
135 if (is_user_prompt) {
136 if (defaultValue != NULL) {
137 SCPrint(TRUE, stdout, CFSTR("%@ [%@]: "), prompt, defaultValue);
138 } else {
139 SCPrint(TRUE, stdout, CFSTR("%@: "), prompt);
140 }
141 }
142
143 /* Get user input */
144 if (fgets(buf, sizeof(buf), stdin) == NULL) {
145 return NULL;
146 }
147
148 /* Prepare for trim */
149 len = (int)strlen(buf);
150 modbuf = buf;
151 modlen = len;
152
153 /* Trim new-line */
154 if ((modlen > 0) && (modbuf[modlen - 1] == '\n')) {
155 modbuf[modlen - 1] = '\0';
156 modlen--;
157 }
158
159 /* If nothing was entered at the user prompt, set default */
160 if (is_user_prompt && defaultValue != NULL && modlen == 0) {
161 CFRetain(defaultValue);
162 return defaultValue;
163 }
164
165 /* Trim spaces from front */
166 while (modlen > 0 && isspace(modbuf[0])) {
167 modbuf = &modbuf[1];
168 modlen--;
169 }
170
171 /* Trim spaces from back */
172 for (i = modlen - 1; i >= 0; i--) {
173 if (isspace(buf[i])) {
174 buf[i] = '\0';
175 modlen--;
176 } else {
177 break;
178 }
179 }
180
181 utf8 = CFStringCreateWithBytes(NULL, (UInt8 *)modbuf, modlen, kCFStringEncodingUTF8, TRUE);
182 return utf8;
183 }
184
185 static char *
186 getLine(char *buf, int len, InputRef src)
187 {
188 int n;
189
190 if (src->el) {
191 int count;
192 const char *line;
193
194 line = el_gets(src->el, &count);
195 if (line == NULL)
196 return NULL;
197
198 strlcpy(buf, line, len);
199 } else {
200 if (fgets(buf, len, src->fp) == NULL)
201 return NULL;
202 }
203
204 n = (int)strlen(buf);
205 if (buf[n-1] == '\n') {
206 /* the entire line fit in the buffer, remove the newline */
207 buf[n-1] = '\0';
208 } else if (!src->el) {
209 /* eat the remainder of the line */
210 do {
211 n = fgetc(src->fp);
212 } while ((n != '\n') && (n != EOF));
213 }
214
215 if (src->h && (buf[0] != '\0')) {
216 HistEvent ev;
217
218 history(src->h, &ev, H_ENTER, buf);
219 }
220
221 return buf;
222 }
223
224
225 static char *
226 getString(char **line)
227 {
228 char *s, *e, c, *string;
229 int i, isQuoted = 0, escaped = 0;
230
231 if (*line == NULL) return NULL;
232 if (**line == '\0') return NULL;
233
234 /* Skip leading white space */
235 while (isspace(**line)) *line += 1;
236
237 /* Grab the next string */
238 s = *line;
239 if (*s == '\0') {
240 return NULL; /* no string available */
241 } else if (*s == '"') {
242 isQuoted = 1; /* it's a quoted string */
243 s++;
244 }
245
246 for (e = s; (c = *e) != '\0'; e++) {
247 if (isQuoted && (c == '"'))
248 break; /* end of quoted string */
249 if (c == '\\') {
250 e++;
251 if (*e == '\0')
252 break; /* if premature end-of-string */
253 if ((*e == '"') || isspace(*e))
254 escaped++; /* if escaped quote or white space */
255 }
256 if (!isQuoted && isspace(c))
257 break; /* end of non-quoted string */
258 }
259
260 string = malloc(e - s - escaped + 1);
261
262 for (i = 0; s < e; s++) {
263 string[i] = *s;
264 if (!((s[0] == '\\') && ((s[1] == '"') || isspace(s[1])))) i++;
265 }
266 string[i] = '\0';
267
268 if (isQuoted)
269 e++; /* move past end of quoted string */
270
271 *line = e;
272 return string;
273 }
274
275
276 __private_extern__
277 Boolean
278 process_line(InputRef src)
279 {
280 char *arg;
281 int argc = 0;
282 char **argv = NULL;
283 int i;
284 char line[LINE_LENGTH];
285 char *s = line;
286
287 // if end-of-file, exit
288 if (getLine(line, sizeof(line), src) == NULL)
289 return FALSE;
290
291 if (nesting > 0) {
292 SCPrint(TRUE, stdout, CFSTR("%d> %s\n"), nesting, line);
293 }
294
295 // break up the input line
296 while ((arg = getString(&s)) != NULL) {
297 if (argc == 0)
298 argv = (char **)malloc(2 * sizeof(char *));
299 else
300 argv = (char **)reallocf(argv, ((argc + 2) * sizeof(char *)));
301 argv[argc++] = arg;
302 }
303
304 if (argc == 0) {
305 return TRUE; // if no arguments
306 }
307
308 /* process the command */
309 if (*argv[0] != '#') {
310 argv[argc] = NULL; // just in case...
311 currentInput = src;
312 do_command(argc, argv);
313 }
314
315 /* free the arguments */
316 for (i = 0; i < argc; i++) {
317 free(argv[i]);
318 }
319 free(argv);
320
321 return !termRequested;
322 }
323
324
325 static void
326 usage(const char *command)
327 {
328 SCPrint(TRUE, stderr, CFSTR("usage: %s\n"), command);
329 SCPrint(TRUE, stderr, CFSTR("\tinteractive access to the dynamic store.\n"));
330 SCPrint(TRUE, stderr, CFSTR("\n"));
331 SCPrint(TRUE, stderr, CFSTR(" or: %s --prefs [preference-file]\n"), command);
332 SCPrint(TRUE, stderr, CFSTR("\tinteractive access to the [raw] stored preferences.\n"));
333 SCPrint(TRUE, stderr, CFSTR("\n"));
334 SCPrint(TRUE, stderr, CFSTR(" or: %s [-W] -r nodename\n"), command);
335 SCPrint(TRUE, stderr, CFSTR(" or: %s [-W] -r address\n"), command);
336 SCPrint(TRUE, stderr, CFSTR(" or: %s [-W] -r local-address remote-address\n"), command);
337 SCPrint(TRUE, stderr, CFSTR("\tcheck reachability of node, address, or address pair (-W to \"watch\").\n"));
338 SCPrint(TRUE, stderr, CFSTR("\n"));
339 SCPrint(TRUE, stderr, CFSTR(" or: %s -w dynamic-store-key [ -t timeout ]\n"), command);
340 SCPrint(TRUE, stderr, CFSTR("\t-w\twait for presense of dynamic store key\n"));
341 SCPrint(TRUE, stderr, CFSTR("\t-t\ttime to wait for key\n"));
342 SCPrint(TRUE, stderr, CFSTR("\n"));
343 SCPrint(TRUE, stderr, CFSTR(" or: %s --get pref\n"), command);
344 SCPrint(TRUE, stderr, CFSTR(" or: %s --set pref [newval]\n"), command);
345 SCPrint(TRUE, stderr, CFSTR(" or: %s --get filename path key \n"), command);
346 SCPrint(TRUE, stderr, CFSTR("\tpref\tdisplay (or set) the specified preference. Valid preferences\n"));
347 SCPrint(TRUE, stderr, CFSTR("\t\tinclude:\n"));
348 SCPrint(TRUE, stderr, CFSTR("\t\t\tComputerName, LocalHostName, HostName\n"));
349 SCPrint(TRUE, stderr, CFSTR("\tnewval\tNew preference value to be set. If not specified,\n"));
350 SCPrint(TRUE, stderr, CFSTR("\t\tthe new value will be read from standard input.\n"));
351 SCPrint(TRUE, stderr, CFSTR("\n"));
352 SCPrint(TRUE, stderr, CFSTR(" or: %s --dns\n"), command);
353 SCPrint(TRUE, stderr, CFSTR("\tshow DNS configuration.\n"));
354 SCPrint(TRUE, stderr, CFSTR("\n"));
355 SCPrint(TRUE, stderr, CFSTR(" or: %s --proxy\n"), command);
356 SCPrint(TRUE, stderr, CFSTR("\tshow \"proxy\" configuration.\n"));
357 SCPrint(TRUE, stderr, CFSTR("\n"));
358 SCPrint(TRUE, stderr, CFSTR(" or: %s --nwi\n"), command);
359 SCPrint(TRUE, stderr, CFSTR("\tshow network information\n"));
360 SCPrint(TRUE, stderr, CFSTR("\n"));
361 SCPrint(TRUE, stderr, CFSTR(" or: %s --nc\n"), command);
362 SCPrint(TRUE, stderr, CFSTR("\tshow VPN network configuration information. Use --nc help for full command list\n"));
363
364 if (_sc_debug) {
365 SCPrint(TRUE, stderr, CFSTR("\n"));
366 SCPrint(TRUE, stderr, CFSTR(" or: %s --log IPMonitor [off|on]\n"), command);
367 SCPrint(TRUE, stderr, CFSTR("\tmanage logging.\n"));
368
369 SCPrint(TRUE, stderr, CFSTR("\n"));
370 SCPrint(TRUE, stderr, CFSTR(" or: %s --disable-until-needed <interfaceName> [on|off ]\n"), command);
371 SCPrint(TRUE, stderr, CFSTR("\tmanage secondary interface demand.\n"));
372 }
373
374 #if !TARGET_OS_IPHONE
375 SCPrint(TRUE, stderr, CFSTR("\n"));
376 SCPrint(TRUE, stderr, CFSTR(" or: %s --allow-new-interfaces [off|on]\n"), command);
377 SCPrint(TRUE, stderr, CFSTR("\tmanage new interface creation with screen locked.\n"));
378 #endif // !TARGET_OS_IPHONE
379
380 if (getenv("ENABLE_EXPERIMENTAL_SCUTIL_COMMANDS")) {
381 SCPrint(TRUE, stderr, CFSTR("\n"));
382 SCPrint(TRUE, stderr, CFSTR(" or: %s --net\n"), command);
383 SCPrint(TRUE, stderr, CFSTR("\tmanage network configuration.\n"));
384 }
385
386 SCPrint(TRUE, stderr, CFSTR("\n"));
387 SCPrint(TRUE, stderr, CFSTR(" or: %s --error err#\n"), command);
388 SCPrint(TRUE, stderr, CFSTR("\tdisplay a descriptive message for the given error code\n"));
389
390 exit (EX_USAGE);
391 }
392
393
394 static char *
395 prompt(EditLine *el)
396 {
397 #pragma unused(el)
398 #if !TARGET_OS_SIMULATOR
399 return "> ";
400 #else // !TARGET_OS_SIMULATOR
401 return "sim> ";
402 #endif // !TARGET_OS_SIMULATOR
403 }
404
405
406 int
407 main(int argc, char * const argv[])
408 {
409 #if !TARGET_OS_IPHONE
410 Boolean allowNewInterfaces = FALSE;
411 #endif // !TARGET_OS_IPHONE
412 Boolean disableUntilNeeded = FALSE;
413 const char * advisoryInterface = NULL;
414 Boolean doAdvisory = FALSE;
415 Boolean doDNS = FALSE;
416 Boolean doNet = FALSE;
417 Boolean doNWI = FALSE;
418 Boolean doPrefs = FALSE;
419 Boolean doProxy = FALSE;
420 Boolean doReach = FALSE;
421 Boolean doSnap = FALSE;
422 char *error = NULL;
423 char *get = NULL;
424 char *log = NULL;
425 extern int optind;
426 int opt;
427 int opti;
428 const char *prog = argv[0];
429 char *renew = NULL;
430 char *set = NULL;
431 char *nc_cmd = NULL;
432 InputRef src;
433 int timeout = 15; /* default timeout (in seconds) */
434 char *wait = NULL;
435 Boolean watch = FALSE;
436 int xStore = 0; /* non dynamic store command line options */
437
438 /* process any arguments */
439
440 while ((opt = getopt_long(argc, argv, "dDvprt:w:W", longopts, &opti)) != -1) {
441 switch(opt) {
442 case 'd':
443 _sc_debug = TRUE;
444 _sc_log = kSCLogDestinationFile; /* enable framework logging */
445 break;
446 case 'D':
447 doDispatch = TRUE;
448 break;
449 case 'v':
450 _sc_verbose = TRUE;
451 _sc_log = kSCLogDestinationFile; /* enable framework logging */
452 break;
453 case 'p':
454 enablePrivateAPI = TRUE;
455 break;
456 case 'r':
457 doReach = TRUE;
458 xStore++;
459 break;
460 case 't':
461 timeout = atoi(optarg);
462 break;
463 case 'w':
464 wait = optarg;
465 xStore++;
466 break;
467 case 'W':
468 watch = TRUE;
469 break;
470 case 0:
471 if (strcmp(longopts[opti].name, "dns") == 0) {
472 doDNS = TRUE;
473 xStore++;
474 } else if (strcmp(longopts[opti].name, "error") == 0) {
475 error = optarg;
476 xStore++;
477 } else if (strcmp(longopts[opti].name, "get") == 0) {
478 get = optarg;
479 xStore++;
480 } else if (strcmp(longopts[opti].name, "nc") == 0) {
481 nc_cmd = optarg;
482 xStore++;
483 } else if (strcmp(longopts[opti].name, "net") == 0) {
484 doNet = TRUE;
485 xStore++;
486 } else if (strcmp(longopts[opti].name, "nwi") == 0) {
487 doNWI = TRUE;
488 xStore++;
489 } else if (strcmp(longopts[opti].name, "prefs") == 0) {
490 doPrefs = TRUE;
491 xStore++;
492 } else if (strcmp(longopts[opti].name, "proxy") == 0) {
493 doProxy = TRUE;
494 xStore++;
495 } else if (strcmp(longopts[opti].name, "renew") == 0) {
496 renew = optarg;
497 xStore++;
498 } else if (strcmp(longopts[opti].name, "set") == 0) {
499 set = optarg;
500 xStore++;
501 } else if (strcmp(longopts[opti].name, "snapshot") == 0) {
502 doSnap = TRUE;
503 xStore++;
504 } else if (strcmp(longopts[opti].name, "log") == 0) {
505 log = optarg;
506 xStore++;
507 #if !TARGET_OS_IPHONE
508 } else if (strcmp(longopts[opti].name, "allow-new-interfaces") == 0) {
509 allowNewInterfaces = TRUE;
510 xStore++;
511 #endif // !TARGET_OS_IPHONE
512 } else if (strcmp(longopts[opti].name, "disable-until-needed") == 0) {
513 disableUntilNeeded = TRUE;
514 xStore++;
515 } else if (strcmp(longopts[opti].name, "user") == 0) {
516 username = CFStringCreateWithCString(NULL, optarg, kCFStringEncodingUTF8);
517 } else if (strcmp(longopts[opti].name, "password") == 0) {
518 password = CFStringCreateWithCString(NULL, optarg, kCFStringEncodingUTF8);
519 } else if (strcmp(longopts[opti].name, "secret") == 0) {
520 sharedsecret = CFStringCreateWithCString(NULL, optarg, kCFStringEncodingUTF8);
521 } else if (strcmp(longopts[opti].name, "advisory") == 0) {
522 doAdvisory = TRUE;
523 advisoryInterface = optarg;
524 xStore++;
525 }
526 break;
527 case '?':
528 default :
529 usage(prog);
530 }
531 }
532
533 argc -= optind;
534 argv += optind;
535
536 if (xStore > 1) {
537 // if we are attempting to process more than one type of request
538 usage(prog);
539 }
540
541 /* are we checking (or watching) the reachability of a host/address */
542 if (doReach) {
543 if (argc < 1) {
544 usage(prog);
545 }
546 if (watch) {
547 do_watchReachability(argc, (char **)argv);
548 } else {
549 do_checkReachability(argc, (char **)argv);
550 }
551 /* NOT REACHED */
552 }
553
554 /* are we waiting on the presense of a dynamic store key */
555 if (wait) {
556 do_wait(wait, timeout);
557 /* NOT REACHED */
558 }
559
560 /* are we looking up the DNS configuration */
561 if (doDNS) {
562 if (watch) {
563 do_watchDNSConfiguration(argc, (char **)argv);
564 } else {
565 do_showDNSConfiguration(argc, (char **)argv);
566 }
567 /* NOT REACHED */
568 }
569
570 if (doNWI) {
571 if (watch) {
572 do_watchNWI(argc, (char**)argv);
573 } else {
574 do_showNWI(argc, (char**)argv);
575 }
576 /* NOT REACHED */
577 }
578
579 if (doSnap) {
580 if (!enablePrivateAPI) {
581 usage(prog);
582 }
583
584 do_open(0, NULL); /* open the dynamic store */
585 do_snapshot(argc, (char**)argv);
586 exit(0);
587 }
588
589 if (doAdvisory) {
590 do_advisory(advisoryInterface, watch, argc, (char**)argv);
591 /* NOT REACHED */
592 }
593
594 /* are we translating error #'s to descriptive text */
595 if (error != NULL) {
596 int sc_status = atoi(error);
597
598 SCPrint(TRUE, stdout, CFSTR("Error: 0x%08x %d %s\n"),
599 sc_status,
600 sc_status,
601 SCErrorString(sc_status));
602 exit(0);
603 }
604
605 /* are we looking up a preference value */
606 if (get) {
607 if (argc == 0) {
608 if (findPref(get) < 0) {
609 usage(prog);
610 }
611 } else if (argc == 2) {
612 /*
613 * extended --get
614 * i.e. scutil --get <filename> <prefs path> <key>
615 *
616 * need to go back one argument to re-use the 1st "--get"
617 * argument as the prefs path name
618 */
619 argc++;
620 argv--;
621 } else {
622 usage(prog);
623 }
624
625 do_getPref(get, argc, (char **)argv);
626 /* NOT REACHED */
627 }
628
629 /* are we looking up the proxy configuration */
630 if (doProxy) {
631 do_showProxyConfiguration(argc, (char **)argv);
632 /* NOT REACHED */
633 }
634
635 /* are we changing a preference value */
636 if (set) {
637 if (findPref(set) < 0) {
638 usage(prog);
639 }
640 do_setPref(set, argc, (char **)argv);
641 /* NOT REACHED */
642 }
643
644 /* verbose log */
645 if (log != NULL) {
646 if (strcasecmp(log, "IPMonitor")) {
647 usage(prog);
648 }
649 do_log(log, argc, (char * *)argv);
650 /* NOT REACHED */
651 }
652
653 #if !TARGET_OS_IPHONE
654 /* allowNewInterfaces */
655 if (allowNewInterfaces) {
656 do_ifnamer("allow-new-interfaces", argc, (char * *)argv);
657 /* NOT REACHED */
658 }
659 #endif // !TARGET_OS_IPHONE
660
661 /* disableUntilNeeded */
662 if (disableUntilNeeded) {
663 do_disable_until_needed(argc, (char * *)argv);
664 /* NOT REACHED */
665 }
666
667 /* network connection commands */
668 if (nc_cmd) {
669 if (find_nc_cmd(nc_cmd) < 0) {
670 usage(prog);
671 }
672 do_nc_cmd(nc_cmd, argc, (char **)argv, watch);
673 /* NOT REACHED */
674 }
675
676 if (doNet) {
677 /* if we are going to be managing the network configuration */
678 commands = (cmdInfo *)commands_net;
679 nCommands = nCommands_net;
680
681 if (!getenv("ENABLE_EXPERIMENTAL_SCUTIL_COMMANDS")) {
682 usage(prog);
683 }
684
685 do_net_init(); /* initialization */
686 do_net_open(argc, (char **)argv); /* open prefs */
687 } else if (doPrefs) {
688 /* if we are going to be managing the network configuration */
689 commands = (cmdInfo *)commands_prefs;
690 nCommands = nCommands_prefs;
691
692 do_dictInit(0, NULL); /* start with an empty dictionary */
693 do_prefs_init(); /* initialization */
694 do_prefs_open(argc, (char **)argv); /* open prefs */
695 } else {
696 /* if we are going to be managing the dynamic store */
697 commands = (cmdInfo *)commands_store;
698 nCommands = nCommands_store;
699
700 do_dictInit(0, NULL); /* start with an empty dictionary */
701 do_open(0, NULL); /* open the dynamic store */
702 }
703
704 /* are we trying to renew a DHCP lease */
705 if (renew != NULL) {
706 do_renew(renew);
707 /* NOT REACHED */
708 }
709
710 /* allocate command input stream */
711 src = (InputRef)CFAllocatorAllocate(NULL, sizeof(Input), 0);
712 src->fp = stdin;
713 src->el = NULL;
714 src->h = NULL;
715
716 if (isatty(fileno(src->fp))) {
717 int editmode = 1;
718 HistEvent ev;
719 struct termios t;
720
721 if (tcgetattr(fileno(src->fp), &t) != -1) {
722 if ((t.c_lflag & ECHO) == 0) {
723 editmode = 0;
724 }
725 }
726 src->el = el_init(prog, src->fp, stdout, stderr);
727 src->h = history_init();
728
729 (void)history(src->h, &ev, H_SETSIZE, INT_MAX);
730 el_set(src->el, EL_HIST, history, src->h);
731
732 if (!editmode) {
733 el_set(src->el, EL_EDITMODE, 0);
734 }
735
736 el_set(src->el, EL_EDITOR, "emacs");
737 el_set(src->el, EL_PROMPT, prompt);
738
739 el_source(src->el, NULL);
740
741 if ((el_get(src->el, EL_EDITMODE, &editmode) != -1) && editmode != 0) {
742 el_set(src->el, EL_SIGNAL, 1);
743 } else {
744 history_end(src->h);
745 src->h = NULL;
746 el_end(src->el);
747 src->el = NULL;
748 }
749 }
750
751 while (TRUE) {
752 Boolean ok;
753
754 ok = process_line(src);
755 if (!ok) {
756 break;
757 }
758 }
759
760 /* close the socket, free resources */
761 if (src->h) history_end(src->h);
762 if (src->el) el_end(src->el);
763 (void)fclose(src->fp);
764 CFAllocatorDeallocate(NULL, src);
765
766 exit (EX_OK); // insure the process exit status is 0
767 return 0; // ...and make main fit the ANSI spec.
768 }