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