/*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
- * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
- * "License"). You may not use this file except in compliance with the
- * License. Please obtain a copy of the License at
- * http://www.apple.com/publicsource and read it before using this file.
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
*
- * This Original Code and all software distributed under the License are
- * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
- * License for the specific language governing rights and limitations
- * under the License.
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
+/*
+ * Modification History
+ *
+ * June 13, 2005 Allan Nathanson <ajn@apple.com>
+ * - added SCPreferences support
+ *
+ * August 4, 2004 Allan Nathanson <ajn@apple.com>
+ * - added network configuration (prefs) support
+ *
+ * September 25, 2002 Allan Nathanson <ajn@apple.com>
+ * - added command line history & editing
+ *
+ * July 9, 2001 Allan Nathanson <ajn@apple.com>
+ * - added "-r" option for checking network reachability
+ * - added "-w" option to check/wait for the presence of a
+ * dynamic store key.
+ *
+ * June 1, 2001 Allan Nathanson <ajn@apple.com>
+ * - public API conversion
+ *
+ * November 9, 2000 Allan Nathanson <ajn@apple.com>
+ * - initial revision
+ */
+
+#include <TargetConditionals.h>
#include <ctype.h>
+#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <unistd.h>
#include <sysexits.h>
#endif /* DEBUG */
#include "scutil.h"
-#include "SCDPrivate.h"
#include "commands.h"
#include "dictionary.h"
+#include "net.h"
+#include "nc.h"
+#include "prefs.h"
+#include "session.h"
+#include "tests.h"
+
+#define LINE_LENGTH 2048
+
+__private_extern__ AuthorizationRef authorization = NULL;
+__private_extern__ InputRef currentInput = NULL;
+__private_extern__ Boolean doDispatch = FALSE;
+__private_extern__ int nesting = 0;
+__private_extern__ SCPreferencesRef ni_prefs = NULL;
+__private_extern__ CFRunLoopRef notifyRl = NULL;
+__private_extern__ CFRunLoopSourceRef notifyRls = NULL;
+__private_extern__ SCPreferencesRef prefs = NULL;
+__private_extern__ char *prefsPath = NULL;
+__private_extern__ SCDynamicStoreRef store = NULL;
+__private_extern__ CFPropertyListRef value = NULL;
+__private_extern__ CFMutableArrayRef watchedKeys = NULL;
+__private_extern__ CFMutableArrayRef watchedPatterns = NULL;
+
+static const struct option longopts[] = {
+// { "debug", no_argument, NULL, 'd' },
+// { "dispatch", no_argument, NULL, 'D' },
+// { "verbose", no_argument, NULL, 'v' },
+// { "SPI", no_argument, NULL, 'p' },
+// { "check-reachability", required_argument, NULL, 'r' },
+// { "timeout", required_argument, NULL, 't' },
+// { "wait-key", required_argument, NULL, 'w' },
+// { "watch-reachability", no_argument, NULL, 'W' },
+ { "configuration", no_argument, NULL, 0 },
+ { "dns", no_argument, NULL, 0 },
+ { "get", required_argument, NULL, 0 },
+ { "error", required_argument, NULL, 0 },
+ { "help", no_argument, NULL, '?' },
+ { "nc", required_argument, NULL, 0 },
+ { "net", no_argument, NULL, 0 },
+ { "nwi", no_argument, NULL, 0 },
+ { "prefs", no_argument, NULL, 0 },
+ { "proxy", no_argument, NULL, 0 },
+ { "renew", required_argument, NULL, 0 },
+ { "set", required_argument, NULL, 0 },
+ { "snapshot", no_argument, NULL, 0 },
+ { "user", required_argument, NULL, 0 },
+ { "password", required_argument, NULL, 0 },
+ { "secret", required_argument, NULL, 0 },
+ { "log", required_argument, NULL, 0 },
+ { "advisory", required_argument, NULL, 0 },
+#if !TARGET_OS_IPHONE
+ { "allow-new-interfaces", no_argument, NULL, 0 },
+#endif // !TARGET_OS_IPHONE
+ { "disable-until-needed", no_argument, NULL, 0 },
+ { NULL, 0, NULL, 0 }
+};
+
+
+__private_extern__
+CFStringRef
+_copyStringFromSTDIN(CFStringRef prompt, CFStringRef defaultValue)
+{
+ char buf[1024];
+ int i;
+ Boolean is_user_prompt = (prompt != NULL && isatty(STDIN_FILENO) && isatty(STDOUT_FILENO));
+ int len;
+ char *modbuf;
+ int modlen;
+ CFStringRef utf8;
+
+ /* Print out a prompt to user that entry is desired */
+ if (is_user_prompt) {
+ if (defaultValue != NULL) {
+ SCPrint(TRUE, stdout, CFSTR("%@ [%@]: "), prompt, defaultValue);
+ } else {
+ SCPrint(TRUE, stdout, CFSTR("%@: "), prompt);
+ }
+ }
+
+ /* Get user input */
+ if (fgets(buf, sizeof(buf), stdin) == NULL) {
+ return NULL;
+ }
-#define LINE_LENGTH 256
+ /* Prepare for trim */
+ len = (int)strlen(buf);
+ modbuf = buf;
+ modlen = len;
-SCDSessionRef session = NULL;
-SCDHandleRef data = NULL;
-int nesting = 0;
-CFMutableArrayRef sources = NULL;
+ /* Trim new-line */
+ if ((modlen > 0) && (modbuf[modlen - 1] == '\n')) {
+ modbuf[modlen - 1] = '\0';
+ modlen--;
+ }
+
+ /* If nothing was entered at the user prompt, set default */
+ if (is_user_prompt && defaultValue != NULL && modlen == 0) {
+ CFRetain(defaultValue);
+ return defaultValue;
+ }
+
+ /* Trim spaces from front */
+ while (modlen > 0 && isspace(modbuf[0])) {
+ modbuf = &modbuf[1];
+ modlen--;
+ }
+
+ /* Trim spaces from back */
+ for (i = modlen - 1; i >= 0; i--) {
+ if (isspace(buf[i])) {
+ buf[i] = '\0';
+ modlen--;
+ } else {
+ break;
+ }
+ }
+ utf8 = CFStringCreateWithBytes(NULL, (UInt8 *)modbuf, modlen, kCFStringEncodingUTF8, TRUE);
+ return utf8;
+}
static char *
-getLine(char *buf, int len, FILE *fp)
+getLine(char *buf, int len, InputRef src)
{
- int x;
+ int n;
- if (fgets(buf, len, fp) == NULL)
- return NULL;
+ if (src->el) {
+ int count;
+ const char *line;
- x = strlen(buf);
- if (buf[x-1] == '\n') {
- /* the entire line fit in the buffer, remove the newline */
- buf[x-1] = '\0';
+ line = el_gets(src->el, &count);
+ if (line == NULL)
+ return NULL;
+
+ strlcpy(buf, line, len);
} else {
+ if (fgets(buf, len, src->fp) == NULL)
+ return NULL;
+ }
+
+ n = (int)strlen(buf);
+ if (buf[n-1] == '\n') {
+ /* the entire line fit in the buffer, remove the newline */
+ buf[n-1] = '\0';
+ } else if (!src->el) {
/* eat the remainder of the line */
do {
- x = fgetc(fp);
- } while ((x != '\n') && (x != EOF));
+ n = fgetc(src->fp);
+ } while ((n != '\n') && (n != EOF));
+ }
+
+ if (src->h && (buf[0] != '\0')) {
+ HistEvent ev;
+
+ history(src->h, &ev, H_ENTER, buf);
}
return buf;
}
-char *
+static char *
getString(char **line)
{
char *s, *e, c, *string;
}
-boolean_t
-process_line(FILE *fp)
+__private_extern__
+Boolean
+process_line(InputRef src)
{
- char line[LINE_LENGTH], *s, *arg, **argv = NULL;
- int i, argc;
-
- /* if end-of-file, exit */
- if (getLine(line, sizeof(line), fp) == NULL)
+ char *arg;
+ int argc = 0;
+ char **argv = NULL;
+ int i;
+ char line[LINE_LENGTH];
+ char *s = line;
+
+ // if end-of-file, exit
+ if (getLine(line, sizeof(line), src) == NULL)
return FALSE;
- if ((nesting > 0) && SCDOptionGet(NULL, kSCDOptionVerbose)) {
- SCDLog(LOG_NOTICE, CFSTR("%d> %s"), nesting, line);
+ if (nesting > 0) {
+ SCPrint(TRUE, stdout, CFSTR("%d> %s\n"), nesting, line);
}
- /* if requested, exit */
- if (strcasecmp(line, "exit") == 0) return FALSE;
- if (strcasecmp(line, "quit") == 0) return FALSE;
- if (strcasecmp(line, "q" ) == 0) return FALSE;
-
- /* break up the input line */
- s = line;
- argc = 0;
+ // break up the input line
while ((arg = getString(&s)) != NULL) {
if (argc == 0)
argv = (char **)malloc(2 * sizeof(char *));
else
- argv = (char **)realloc(argv, ((argc + 2) * sizeof(char *)));
+ argv = (char **)reallocf(argv, ((argc + 2) * sizeof(char *)));
argv[argc++] = arg;
}
- /* process the command */
- if (argc > 0) {
- argv[argc] = NULL; /* just in case... */
+ if (argc == 0) {
+ return TRUE; // if no arguments
+ }
- if (*argv[0] != '#')
- do_command(argc, argv);
+ /* process the command */
+ if (*argv[0] != '#') {
+ argv[argc] = NULL; // just in case...
+ currentInput = src;
+ do_command(argc, argv);
+ }
- for (i = 0; i < argc; i++)
- free(argv[i]);
- free(argv);
+ /* free the arguments */
+ for (i = 0; i < argc; i++) {
+ free(argv[i]);
}
+ free(argv);
- return TRUE;
+ return !termRequested;
}
-void
-runLoopProcessInput(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info)
+static void
+usage(const char *command)
{
- FILE *fp = info;
-
- if (process_line(fp) == FALSE) {
- /* we don't want any more input from this stream, stop listening */
- CFRunLoopRemoveSource(CFRunLoopGetCurrent(),
- (CFRunLoopSourceRef)CFArrayGetValueAtIndex(sources, 0),
- kCFRunLoopDefaultMode);
-
- /* we no longer need the fd (socket) */
- CFSocketInvalidate(s);
+ SCPrint(TRUE, stderr, CFSTR("usage: %s\n"), command);
+ SCPrint(TRUE, stderr, CFSTR("\tinteractive access to the dynamic store.\n"));
+ SCPrint(TRUE, stderr, CFSTR("\n"));
+ SCPrint(TRUE, stderr, CFSTR(" or: %s --prefs [preference-file]\n"), command);
+ SCPrint(TRUE, stderr, CFSTR("\tinteractive access to the [raw] stored preferences.\n"));
+ SCPrint(TRUE, stderr, CFSTR("\n"));
+ SCPrint(TRUE, stderr, CFSTR(" or: %s [-W] -r nodename\n"), command);
+ SCPrint(TRUE, stderr, CFSTR(" or: %s [-W] -r address\n"), command);
+ SCPrint(TRUE, stderr, CFSTR(" or: %s [-W] -r local-address remote-address\n"), command);
+ SCPrint(TRUE, stderr, CFSTR("\tcheck reachability of node, address, or address pair (-W to \"watch\").\n"));
+ SCPrint(TRUE, stderr, CFSTR("\n"));
+ SCPrint(TRUE, stderr, CFSTR(" or: %s -w dynamic-store-key [ -t timeout ]\n"), command);
+ SCPrint(TRUE, stderr, CFSTR("\t-w\twait for presense of dynamic store key\n"));
+ SCPrint(TRUE, stderr, CFSTR("\t-t\ttime to wait for key\n"));
+ SCPrint(TRUE, stderr, CFSTR("\n"));
+ SCPrint(TRUE, stderr, CFSTR(" or: %s --get pref\n"), command);
+ SCPrint(TRUE, stderr, CFSTR(" or: %s --set pref [newval]\n"), command);
+ SCPrint(TRUE, stderr, CFSTR(" or: %s --get filename path key \n"), command);
+ SCPrint(TRUE, stderr, CFSTR("\tpref\tdisplay (or set) the specified preference. Valid preferences\n"));
+ SCPrint(TRUE, stderr, CFSTR("\t\tinclude:\n"));
+ SCPrint(TRUE, stderr, CFSTR("\t\t\tComputerName, LocalHostName, HostName\n"));
+ SCPrint(TRUE, stderr, CFSTR("\tnewval\tNew preference value to be set. If not specified,\n"));
+ SCPrint(TRUE, stderr, CFSTR("\t\tthe new value will be read from standard input.\n"));
+ SCPrint(TRUE, stderr, CFSTR("\n"));
+ SCPrint(TRUE, stderr, CFSTR(" or: %s --dns\n"), command);
+ SCPrint(TRUE, stderr, CFSTR("\tshow DNS configuration.\n"));
+ SCPrint(TRUE, stderr, CFSTR("\n"));
+ SCPrint(TRUE, stderr, CFSTR(" or: %s --proxy\n"), command);
+ SCPrint(TRUE, stderr, CFSTR("\tshow \"proxy\" configuration.\n"));
+ SCPrint(TRUE, stderr, CFSTR("\n"));
+ SCPrint(TRUE, stderr, CFSTR(" or: %s --nwi\n"), command);
+ SCPrint(TRUE, stderr, CFSTR("\tshow network information\n"));
+ SCPrint(TRUE, stderr, CFSTR("\n"));
+ SCPrint(TRUE, stderr, CFSTR(" or: %s --nc\n"), command);
+ SCPrint(TRUE, stderr, CFSTR("\tshow VPN network configuration information. Use --nc help for full command list\n"));
+
+ if (_sc_debug) {
+ SCPrint(TRUE, stderr, CFSTR("\n"));
+ SCPrint(TRUE, stderr, CFSTR(" or: %s --log IPMonitor [off|on]\n"), command);
+ SCPrint(TRUE, stderr, CFSTR("\tmanage logging.\n"));
+
+ SCPrint(TRUE, stderr, CFSTR("\n"));
+ SCPrint(TRUE, stderr, CFSTR(" or: %s --disable-until-needed <interfaceName> [on|off ]\n"), command);
+ SCPrint(TRUE, stderr, CFSTR("\tmanage secondary interface demand.\n"));
+ }
- /* we no longer need to track this source */
- CFArrayRemoveValueAtIndex(sources, 0);
+#if !TARGET_OS_IPHONE
+ SCPrint(TRUE, stderr, CFSTR("\n"));
+ SCPrint(TRUE, stderr, CFSTR(" or: %s --allow-new-interfaces [off|on]\n"), command);
+ SCPrint(TRUE, stderr, CFSTR("\tmanage new interface creation with screen locked.\n"));
+#endif // !TARGET_OS_IPHONE
- if (CFArrayGetCount(sources) > 0) {
- /* add the previous input source to the run loop */
- CFRunLoopAddSource(CFRunLoopGetCurrent(),
- (CFRunLoopSourceRef)CFArrayGetValueAtIndex(sources, 0),
- kCFRunLoopDefaultMode);
- } else {
- /* no more input sources, we're done! */
- exit (EX_OK);
- }
-
- /* decrement the nesting level */
- nesting--;
+ if (getenv("ENABLE_EXPERIMENTAL_SCUTIL_COMMANDS")) {
+ SCPrint(TRUE, stderr, CFSTR("\n"));
+ SCPrint(TRUE, stderr, CFSTR(" or: %s --net\n"), command);
+ SCPrint(TRUE, stderr, CFSTR("\tmanage network configuration.\n"));
}
- if (SCDOptionGet(NULL, kSCDOptionUseCFRunLoop)) {
- /* debug information, diagnostics */
- _showMachPortStatus();
+ SCPrint(TRUE, stderr, CFSTR("\n"));
+ SCPrint(TRUE, stderr, CFSTR(" or: %s --error err#\n"), command);
+ SCPrint(TRUE, stderr, CFSTR("\tdisplay a descriptive message for the given error code\n"));
- /* if necessary, re-issue prompt */
- if ((CFArrayGetCount(sources) == 1) && isatty(STDIN_FILENO)) {
- printf("> ");
- fflush(stdout);
- }
- }
+ exit (EX_USAGE);
+}
- return;
+
+static char *
+prompt(EditLine *el)
+{
+#pragma unused(el)
+#if !TARGET_OS_SIMULATOR
+ return "> ";
+#else // !TARGET_OS_SIMULATOR
+ return "sim> ";
+#endif // !TARGET_OS_SIMULATOR
}
int
-main(int argc, const char *argv[])
+main(int argc, char * const argv[])
{
- extern int optind;
- int opt;
- boolean_t ok;
+ const char * advisoryInterface = NULL;
+#if !TARGET_OS_IPHONE
+ Boolean allowNewInterfaces = FALSE;
+#endif // !TARGET_OS_IPHONE
+ Boolean configuration = FALSE;
+ Boolean disableUntilNeeded = FALSE;
+ Boolean doAdvisory = FALSE;
+ Boolean doDNS = FALSE;
+ Boolean doNet = FALSE;
+ Boolean doNWI = FALSE;
+ Boolean doPrefs = FALSE;
+ Boolean doProxy = FALSE;
+ Boolean doReach = FALSE;
+ Boolean doSnap = FALSE;
+ char *error = NULL;
+ char *get = NULL;
+ char *log = NULL;
+ extern int optind;
+ int opt;
+ int opti;
+ const char *prog = argv[0];
+ char *renew = NULL;
+ char *set = NULL;
+ char *nc_cmd = NULL;
+ InputRef src;
+ int timeout = 15; /* default timeout (in seconds) */
+ char *wait = NULL;
+ Boolean watch = FALSE;
+ int xStore = 0; /* non dynamic store command line options */
/* process any arguments */
- SCDOptionSet(NULL, kSCDOptionUseCFRunLoop, FALSE);
-
- while ((opt = getopt(argc, argv, "dvr")) != -1)
+ while ((opt = getopt_long(argc, argv, "dDvprt:w:W", longopts, &opti)) != -1) {
switch(opt) {
case 'd':
- SCDOptionSet(NULL, kSCDOptionDebug, TRUE);
+ _sc_debug = TRUE;
+ _sc_log = kSCLogDestinationFile; /* enable framework logging */
+ break;
+ case 'D':
+ doDispatch = TRUE;
break;
case 'v':
- SCDOptionSet(NULL, kSCDOptionVerbose, TRUE);
+ _sc_verbose = TRUE;
+ _sc_log = kSCLogDestinationFile; /* enable framework logging */
+ break;
+ case 'p':
+ enablePrivateAPI = TRUE;
break;
case 'r':
- SCDOptionSet(NULL, kSCDOptionUseCFRunLoop, TRUE);
+ doReach = TRUE;
+ xStore++;
+ break;
+ case 't':
+ timeout = atoi(optarg);
+ break;
+ case 'w':
+ wait = optarg;
+ xStore++;
+ break;
+ case 'W':
+ watch = TRUE;
+ break;
+ case 0:
+ if (strcmp(longopts[opti].name, "configuration") == 0) {
+ configuration = TRUE;
+ xStore++;
+ } else if (strcmp(longopts[opti].name, "dns") == 0) {
+ doDNS = TRUE;
+ xStore++;
+ } else if (strcmp(longopts[opti].name, "error") == 0) {
+ error = optarg;
+ xStore++;
+ } else if (strcmp(longopts[opti].name, "get") == 0) {
+ get = optarg;
+ xStore++;
+ } else if (strcmp(longopts[opti].name, "nc") == 0) {
+ nc_cmd = optarg;
+ xStore++;
+ } else if (strcmp(longopts[opti].name, "net") == 0) {
+ doNet = TRUE;
+ xStore++;
+ } else if (strcmp(longopts[opti].name, "nwi") == 0) {
+ doNWI = TRUE;
+ xStore++;
+ } else if (strcmp(longopts[opti].name, "prefs") == 0) {
+ doPrefs = TRUE;
+ xStore++;
+ } else if (strcmp(longopts[opti].name, "proxy") == 0) {
+ doProxy = TRUE;
+ xStore++;
+ } else if (strcmp(longopts[opti].name, "renew") == 0) {
+ renew = optarg;
+ xStore++;
+ } else if (strcmp(longopts[opti].name, "set") == 0) {
+ set = optarg;
+ xStore++;
+ } else if (strcmp(longopts[opti].name, "snapshot") == 0) {
+ doSnap = TRUE;
+ xStore++;
+ } else if (strcmp(longopts[opti].name, "log") == 0) {
+ log = optarg;
+ xStore++;
+#if !TARGET_OS_IPHONE
+ } else if (strcmp(longopts[opti].name, "allow-new-interfaces") == 0) {
+ allowNewInterfaces = TRUE;
+ xStore++;
+#endif // !TARGET_OS_IPHONE
+ } else if (strcmp(longopts[opti].name, "disable-until-needed") == 0) {
+ disableUntilNeeded = TRUE;
+ xStore++;
+ } else if (strcmp(longopts[opti].name, "user") == 0) {
+ username = CFStringCreateWithCString(NULL, optarg, kCFStringEncodingUTF8);
+ } else if (strcmp(longopts[opti].name, "password") == 0) {
+ password = CFStringCreateWithCString(NULL, optarg, kCFStringEncodingUTF8);
+ } else if (strcmp(longopts[opti].name, "secret") == 0) {
+ sharedsecret = CFStringCreateWithCString(NULL, optarg, kCFStringEncodingUTF8);
+ } else if (strcmp(longopts[opti].name, "advisory") == 0) {
+ doAdvisory = TRUE;
+ advisoryInterface = optarg;
+ xStore++;
+ }
break;
case '?':
default :
- do_help(0, NULL);
+ usage(prog);
+ }
}
+
argc -= optind;
argv += optind;
- /* start with an empty dictionary */
- do_dictInit(0, NULL);
+ if (xStore > 1) {
+ // if we are attempting to process more than one type of request
+ usage(prog);
+ }
+
+ /* are we asking for a configuration summary */
+ if (configuration) {
+ do_configuration(argc, (char **)argv);
+ /* NOT REACHED */
+ }
+
+ /* are we checking (or watching) the reachability of a host/address */
+ if (doReach) {
+ if (argc < 1) {
+ usage(prog);
+ }
+ if (watch) {
+ do_watchReachability(argc, (char **)argv);
+ } else {
+ do_checkReachability(argc, (char **)argv);
+ }
+ /* NOT REACHED */
+ }
+
+ /* are we waiting on the presense of a dynamic store key */
+ if (wait) {
+ do_wait(wait, timeout);
+ /* NOT REACHED */
+ }
+
+ /* are we looking up the DNS configuration */
+ if (doDNS) {
+ if (watch) {
+ do_watchDNSConfiguration(argc, (char **)argv);
+ } else {
+ do_showDNSConfiguration(argc, (char **)argv);
+ }
+ /* NOT REACHED */
+ }
+
+ if (doNWI) {
+ if (watch) {
+ do_watchNWI(argc, (char**)argv);
+ } else {
+ do_showNWI(argc, (char**)argv);
+ }
+ /* NOT REACHED */
+ }
+
+ if (doSnap) {
+ if (!enablePrivateAPI) {
+ usage(prog);
+ }
+
+ do_open(0, NULL); /* open the dynamic store */
+ do_snapshot(argc, (char**)argv);
+ exit(0);
+ }
+
+ if (doAdvisory) {
+ do_advisory(advisoryInterface, watch, argc, (char**)argv);
+ /* NOT REACHED */
+ }
+
+ /* are we translating error #'s to descriptive text */
+ if (error != NULL) {
+ int sc_status = atoi(error);
+
+ SCPrint(TRUE, stdout, CFSTR("Error: 0x%08x %d %s\n"),
+ sc_status,
+ sc_status,
+ SCErrorString(sc_status));
+ exit(0);
+ }
+
+ /* are we looking up a preference value */
+ if (get) {
+ if (argc == 0) {
+ if (findPref(get) < 0) {
+ usage(prog);
+ }
+ } else if (argc == 2) {
+ /*
+ * extended --get
+ * i.e. scutil --get <filename> <prefs path> <key>
+ *
+ * need to go back one argument to re-use the 1st "--get"
+ * argument as the prefs path name
+ */
+ argc++;
+ argv--;
+ } else {
+ usage(prog);
+ }
+
+ do_getPref(get, argc, (char **)argv);
+ /* NOT REACHED */
+ }
- if (SCDOptionGet(NULL, kSCDOptionUseCFRunLoop)) {
- CFSocketRef in;
- CFSocketContext context = { 0, stdin, NULL, NULL, NULL };
- CFRunLoopSourceRef rls;
+ /* are we looking up the proxy configuration */
+ if (doProxy) {
+ do_showProxyConfiguration(argc, (char **)argv);
+ /* NOT REACHED */
+ }
- /* create a "socket" reference with the file descriptor associated with stdin */
- in = CFSocketCreateWithNative(NULL,
- STDIN_FILENO,
- kCFSocketReadCallBack,
- runLoopProcessInput,
- &context);
+ /* are we changing a preference value */
+ if (set) {
+ if (findPref(set) < 0) {
+ usage(prog);
+ }
+ do_setPref(set, argc, (char **)argv);
+ /* NOT REACHED */
+ }
- /* Create a run loop source for the (stdin) file descriptor */
- rls = CFSocketCreateRunLoopSource(NULL, in, nesting);
+ /* verbose log */
+ if (log != NULL) {
+ if (strcasecmp(log, "IPMonitor")) {
+ usage(prog);
+ }
+ do_log(log, argc, (char * *)argv);
+ /* NOT REACHED */
+ }
- /* keep track of input file sources */
- sources = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
- CFArrayAppendValue(sources, rls);
+#if !TARGET_OS_IPHONE
+ /* allowNewInterfaces */
+ if (allowNewInterfaces) {
+ do_ifnamer("allow-new-interfaces", argc, (char * *)argv);
+ /* NOT REACHED */
+ }
+#endif // !TARGET_OS_IPHONE
- /* add this source to the run loop */
- CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
+ /* disableUntilNeeded */
+ if (disableUntilNeeded) {
+ do_disable_until_needed(argc, (char * *)argv);
+ /* NOT REACHED */
+ }
- CFRelease(rls);
- CFRelease(in);
+ /* network connection commands */
+ if (nc_cmd) {
+ if (find_nc_cmd(nc_cmd) < 0) {
+ usage(prog);
+ }
+ do_nc_cmd(nc_cmd, argc, (char **)argv, watch);
+ /* NOT REACHED */
}
- do {
- /* debug information, diagnostics */
- _showMachPortStatus();
+ if (doNet) {
+ /* if we are going to be managing the network configuration */
+ commands = (cmdInfo *)commands_net;
+ nCommands = nCommands_net;
- /* issue prompt */
- if (isatty(STDIN_FILENO)) {
- printf("> ");
- fflush(stdout);
+ if (!getenv("ENABLE_EXPERIMENTAL_SCUTIL_COMMANDS")) {
+ usage(prog);
}
- if (SCDOptionGet(NULL, kSCDOptionUseCFRunLoop)) {
- CFRunLoopRun(); /* process input, process events */
- ok = FALSE; /* if the RunLoop exited */
+ do_net_init(); /* initialization */
+ do_net_open(argc, (char **)argv); /* open prefs */
+ } else if (doPrefs) {
+ /* if we are going to be managing the network configuration */
+ commands = (cmdInfo *)commands_prefs;
+ nCommands = nCommands_prefs;
+
+ do_dictInit(0, NULL); /* start with an empty dictionary */
+ do_prefs_init(); /* initialization */
+ do_prefs_open(argc, (char **)argv); /* open prefs */
+ } else {
+ /* if we are going to be managing the dynamic store */
+ commands = (cmdInfo *)commands_store;
+ nCommands = nCommands_store;
+
+ do_dictInit(0, NULL); /* start with an empty dictionary */
+ do_open(0, NULL); /* open the dynamic store */
+ }
+
+ /* are we trying to renew a DHCP lease */
+ if (renew != NULL) {
+ do_renew(renew);
+ /* NOT REACHED */
+ }
+
+ /* allocate command input stream */
+ src = (InputRef)CFAllocatorAllocate(NULL, sizeof(Input), 0);
+ src->fp = stdin;
+ src->el = NULL;
+ src->h = NULL;
+
+ if (isatty(fileno(src->fp))) {
+ int editmode = 1;
+ HistEvent ev;
+ struct termios t;
+
+ if (tcgetattr(fileno(src->fp), &t) != -1) {
+ if ((t.c_lflag & ECHO) == 0) {
+ editmode = 0;
+ }
+ }
+ src->el = el_init(prog, src->fp, stdout, stderr);
+ src->h = history_init();
+
+ (void)history(src->h, &ev, H_SETSIZE, INT_MAX);
+ el_set(src->el, EL_HIST, history, src->h);
+
+ if (!editmode) {
+ el_set(src->el, EL_EDITMODE, 0);
+ }
+
+ el_set(src->el, EL_EDITOR, "emacs");
+ el_set(src->el, EL_PROMPT, prompt);
+
+ el_source(src->el, NULL);
+
+ if ((el_get(src->el, EL_EDITMODE, &editmode) != -1) && editmode != 0) {
+ el_set(src->el, EL_SIGNAL, 1);
} else {
- /* process command */
- ok = process_line(stdin);
+ history_end(src->h);
+ src->h = NULL;
+ el_end(src->el);
+ src->el = NULL;
}
- } while (ok);
+ }
+
+ while (TRUE) {
+ Boolean ok;
+
+ ok = process_line(src);
+ if (!ok) {
+ break;
+ }
+ }
+
+ /* close the socket, free resources */
+ if (src->h) history_end(src->h);
+ if (src->el) el_end(src->el);
+ (void)fclose(src->fp);
+ CFAllocatorDeallocate(NULL, src);
exit (EX_OK); // insure the process exit status is 0
return 0; // ...and make main fit the ANSI spec.