2 * Copyright (c) 2000-2009 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * June 13, 2005 Allan Nathanson <ajn@apple.com>
28 * - added SCPreferences support
30 * August 4, 2004 Allan Nathanson <ajn@apple.com>
31 * - added network configuration (prefs) support
33 * September 25, 2002 Allan Nathanson <ajn@apple.com>
34 * - added command line history & editing
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
41 * June 1, 2001 Allan Nathanson <ajn@apple.com>
42 * - public API conversion
44 * November 9, 2000 Allan Nathanson <ajn@apple.com>
58 #include <mach/mach.h>
59 #include <mach/mach_error.h>
64 #include "dictionary.h"
71 #define LINE_LENGTH 256
74 __private_extern__ AuthorizationRef authorization
= NULL
;
75 __private_extern__ InputRef currentInput
= NULL
;
76 __private_extern__
int nesting
= 0;
77 __private_extern__ CFRunLoopRef notifyRl
= NULL
;
78 __private_extern__ CFRunLoopSourceRef notifyRls
= NULL
;
79 __private_extern__ SCPreferencesRef prefs
= NULL
;
80 __private_extern__ SCDynamicStoreRef store
= NULL
;
81 __private_extern__ CFPropertyListRef value
= NULL
;
82 __private_extern__ CFMutableArrayRef watchedKeys
= NULL
;
83 __private_extern__ CFMutableArrayRef watchedPatterns
= NULL
;
85 static const struct option longopts
[] = {
86 // { "debug", no_argument, NULL, 'd' },
87 // { "verbose", no_argument, NULL, 'v' },
88 // { "SPI", no_argument, NULL, 'p' },
89 // { "check-reachability", required_argument, NULL, 'r' },
90 // { "timeout", required_argument, NULL, 't' },
91 // { "wait-key", required_argument, NULL, 'w' },
92 { "dns", no_argument
, NULL
, 0 },
93 { "get", required_argument
, NULL
, 0 },
94 { "help", no_argument
, NULL
, '?' },
95 { "net", no_argument
, NULL
, 0 },
96 { "prefs", no_argument
, NULL
, 0 },
97 { "proxy", no_argument
, NULL
, 0 },
98 { "set", required_argument
, NULL
, 0 },
104 getLine(char *buf
, int len
, InputRef src
)
112 line
= el_gets(src
->el
, &count
);
116 strncpy(buf
, line
, len
);
118 if (fgets(buf
, len
, src
->fp
) == NULL
)
123 if (buf
[n
-1] == '\n') {
124 /* the entire line fit in the buffer, remove the newline */
126 } else if (!src
->el
) {
127 /* eat the remainder of the line */
130 } while ((n
!= '\n') && (n
!= EOF
));
136 history(src
->h
, &ev
, H_ENTER
, buf
);
145 getString(char **line
)
147 char *s
, *e
, c
, *string
;
148 int i
, isQuoted
= 0, escaped
= 0;
150 if (*line
== NULL
) return NULL
;
151 if (**line
== '\0') return NULL
;
153 /* Skip leading white space */
154 while (isspace(**line
)) *line
+= 1;
156 /* Grab the next string */
159 return NULL
; /* no string available */
160 } else if (*s
== '"') {
161 isQuoted
= 1; /* it's a quoted string */
165 for (e
= s
; (c
= *e
) != '\0'; e
++) {
166 if (isQuoted
&& (c
== '"'))
167 break; /* end of quoted string */
171 break; /* if premature end-of-string */
172 if ((*e
== '"') || isspace(*e
))
173 escaped
++; /* if escaped quote or white space */
175 if (!isQuoted
&& isspace(c
))
176 break; /* end of non-quoted string */
179 string
= malloc(e
- s
- escaped
+ 1);
181 for (i
= 0; s
< e
; s
++) {
183 if (!((s
[0] == '\\') && ((s
[1] == '"') || isspace(s
[1])))) i
++;
188 e
++; /* move past end of quoted string */
197 process_line(InputRef src
)
203 char line
[LINE_LENGTH
];
206 // if end-of-file, exit
207 if (getLine(line
, sizeof(line
), src
) == NULL
)
211 SCPrint(TRUE
, stdout
, CFSTR("%d> %s\n"), nesting
, line
);
214 // break up the input line
215 while ((arg
= getString(&s
)) != NULL
) {
217 argv
= (char **)malloc(2 * sizeof(char *));
219 argv
= (char **)reallocf(argv
, ((argc
+ 2) * sizeof(char *)));
224 return TRUE
; // if no arguments
227 /* process the command */
228 if (*argv
[0] != '#') {
229 argv
[argc
] = NULL
; // just in case...
231 do_command(argc
, argv
);
234 /* free the arguments */
235 for (i
= 0; i
< argc
; i
++) {
240 return !termRequested
;
245 usage(const char *command
)
247 SCPrint(TRUE
, stderr
, CFSTR("usage: %s\n"), command
);
248 SCPrint(TRUE
, stderr
, CFSTR("\tinteractive access to the dynamic store.\n"));
249 SCPrint(TRUE
, stderr
, CFSTR("\n"));
250 SCPrint(TRUE
, stderr
, CFSTR(" or: %s --prefs\n"), command
);
251 SCPrint(TRUE
, stderr
, CFSTR("\tinteractive access to the [raw] stored preferences.\n"));
252 SCPrint(TRUE
, stderr
, CFSTR("\n"));
253 SCPrint(TRUE
, stderr
, CFSTR(" or: %s [-W] -r nodename\n"), command
);
254 SCPrint(TRUE
, stderr
, CFSTR(" or: %s [-W] -r address\n"), command
);
255 SCPrint(TRUE
, stderr
, CFSTR(" or: %s [-W] -r local-address remote-address\n"), command
);
256 SCPrint(TRUE
, stderr
, CFSTR("\tcheck reachability of node, address, or address pair (-W to \"watch\").\n"));
257 SCPrint(TRUE
, stderr
, CFSTR("\n"));
258 SCPrint(TRUE
, stderr
, CFSTR(" or: %s -w dynamic-store-key [ -t timeout ]\n"), command
);
259 SCPrint(TRUE
, stderr
, CFSTR("\t-w\twait for presense of dynamic store key\n"));
260 SCPrint(TRUE
, stderr
, CFSTR("\t-t\ttime to wait for key\n"));
261 SCPrint(TRUE
, stderr
, CFSTR("\n"));
262 SCPrint(TRUE
, stderr
, CFSTR(" or: %s --get pref\n"), command
);
263 SCPrint(TRUE
, stderr
, CFSTR(" or: %s --set pref [newval]\n"), command
);
264 SCPrint(TRUE
, stderr
, CFSTR("\tpref\tdisplay (or set) the specified preference. Valid preferences\n"));
265 SCPrint(TRUE
, stderr
, CFSTR("\t\tinclude:\n"));
266 SCPrint(TRUE
, stderr
, CFSTR("\t\t\tComputerName, LocalHostName, HostName\n"));
267 SCPrint(TRUE
, stderr
, CFSTR("\tnewval\tNew preference value to be set. If not specified,\n"));
268 SCPrint(TRUE
, stderr
, CFSTR("\t\tthe new value will be read from standard input.\n"));
269 SCPrint(TRUE
, stderr
, CFSTR("\n"));
270 SCPrint(TRUE
, stderr
, CFSTR(" or: %s --dns\n"), command
);
271 SCPrint(TRUE
, stderr
, CFSTR("\tshow DNS configuration.\n"));
272 SCPrint(TRUE
, stderr
, CFSTR("\n"));
273 SCPrint(TRUE
, stderr
, CFSTR(" or: %s --proxy\n"), command
);
274 SCPrint(TRUE
, stderr
, CFSTR("\tshow \"proxy\" configuration.\n"));
276 if (getenv("ENABLE_EXPERIMENTAL_SCUTIL_COMMANDS")) {
277 SCPrint(TRUE
, stderr
, CFSTR("\n"));
278 SCPrint(TRUE
, stderr
, CFSTR(" or: %s --net\n"), command
);
279 SCPrint(TRUE
, stderr
, CFSTR("\tmanage network configuration.\n"));
294 main(int argc
, char * const argv
[])
296 Boolean doDNS
= FALSE
;
297 Boolean doNet
= FALSE
;
298 Boolean doPrefs
= FALSE
;
299 Boolean doProxy
= FALSE
;
300 Boolean doReach
= FALSE
;
305 const char *prog
= argv
[0];
308 int timeout
= 15; /* default timeout (in seconds) */
310 Boolean watch
= FALSE
;
311 int xStore
= 0; /* non dynamic store command line options */
313 /* process any arguments */
315 while ((opt
= getopt_long(argc
, argv
, "dvprt:w:W", longopts
, &opti
)) != -1)
319 _sc_log
= FALSE
; /* enable framework logging */
323 _sc_log
= FALSE
; /* enable framework logging */
326 enablePrivateAPI
= TRUE
;
333 timeout
= atoi(optarg
);
343 if (strcmp(longopts
[opti
].name
, "dns") == 0) {
346 } else if (strcmp(longopts
[opti
].name
, "get") == 0) {
349 } else if (strcmp(longopts
[opti
].name
, "net") == 0) {
352 } else if (strcmp(longopts
[opti
].name
, "prefs") == 0) {
355 } else if (strcmp(longopts
[opti
].name
, "proxy") == 0) {
358 } else if (strcmp(longopts
[opti
].name
, "set") == 0) {
371 // if we are attempting to process more than one type of request
375 /* are we checking (or watching) the reachability of a host/address */
381 do_watchReachability(argc
, (char **)argv
);
383 do_checkReachability(argc
, (char **)argv
);
388 /* are we waiting on the presense of a dynamic store key */
390 do_wait(wait
, timeout
);
394 /* are we looking up the DNS configuration */
396 do_showDNSConfiguration(argc
, (char **)argv
);
400 /* are we looking up a preference value */
402 if (findPref(get
) < 0) {
405 do_getPref(get
, argc
, (char **)argv
);
409 /* are we looking up the proxy configuration */
411 do_showProxyConfiguration(argc
, (char **)argv
);
415 /* are we changing a preference value */
417 if (findPref(set
) < 0) {
420 do_setPref(set
, argc
, (char **)argv
);
425 /* if we are going to be managing the network configuration */
426 commands
= (cmdInfo
*)commands_net
;
427 nCommands
= nCommands_net
;
429 if (!getenv("ENABLE_EXPERIMENTAL_SCUTIL_COMMANDS")) {
433 do_net_init(); /* initialization */
434 do_net_open(0, NULL
); /* open default prefs */
435 } else if (doPrefs
) {
436 /* if we are going to be managing the network configuration */
437 commands
= (cmdInfo
*)commands_prefs
;
438 nCommands
= nCommands_prefs
;
440 do_dictInit(0, NULL
); /* start with an empty dictionary */
441 do_prefs_init(); /* initialization */
442 do_prefs_open(0, NULL
); /* open default prefs */
444 /* if we are going to be managing the dynamic store */
445 commands
= (cmdInfo
*)commands_store
;
446 nCommands
= nCommands_store
;
448 do_dictInit(0, NULL
); /* start with an empty dictionary */
449 do_open(0, NULL
); /* open the dynamic store */
452 /* allocate command input stream */
453 src
= (InputRef
)CFAllocatorAllocate(NULL
, sizeof(Input
), 0);
458 if (isatty(fileno(src
->fp
))) {
463 if (tcgetattr(fileno(src
->fp
), &t
) != -1) {
464 if ((t
.c_lflag
& ECHO
) == 0) {
468 src
->el
= el_init(prog
, src
->fp
, stdout
, stderr
);
469 src
->h
= history_init();
471 (void)history(src
->h
, &ev
, H_SETSIZE
, INT_MAX
);
472 el_set(src
->el
, EL_HIST
, history
, src
->h
);
475 el_set(src
->el
, EL_EDITMODE
, 0);
478 el_set(src
->el
, EL_EDITOR
, "emacs");
479 el_set(src
->el
, EL_PROMPT
, prompt
);
481 el_source(src
->el
, NULL
);
483 if ((el_get(src
->el
, EL_EDITMODE
, &editmode
) != -1) && editmode
!= 0) {
484 el_set(src
->el
, EL_SIGNAL
, 1);
496 ok
= process_line(src
);
502 /* close the socket, free resources */
503 if (src
->h
) history_end(src
->h
);
504 if (src
->el
) el_end(src
->el
);
505 (void)fclose(src
->fp
);
506 CFAllocatorDeallocate(NULL
, src
);
508 exit (EX_OK
); // insure the process exit status is 0
509 return 0; // ...and make main fit the ANSI spec.