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