2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
27 * Modification History
29 * September 25, 2002 Allan Nathanson <ajn@apple.com>
30 * - added command line history & editing
32 * July 9, 2001 Allan Nathanson <ajn@apple.com>
33 * - added "-r" option for checking network reachability
34 * - added "-w" option to check/wait for the presence of a
37 * June 1, 2001 Allan Nathanson <ajn@apple.com>
38 * - public API conversion
40 * November 9, 2000 Allan Nathanson <ajn@apple.com>
54 #include <mach/mach.h>
55 #include <mach/mach_error.h>
60 #include "dictionary.h"
64 #include "SCDynamicStoreInternal.h"
67 #define LINE_LENGTH 256
71 CFRunLoopRef notifyRl
= NULL
;
72 CFRunLoopSourceRef notifyRls
= NULL
;
73 SCDynamicStoreRef store
= NULL
;
74 CFPropertyListRef value
= NULL
;
75 CFMutableArrayRef watchedKeys
= NULL
;
76 CFMutableArrayRef watchedPatterns
= NULL
;
78 static struct option longopts
[] = {
79 // { "debug", no_argument, NULL, 'd' },
80 // { "verbose", no_argument, NULL, 'v' },
81 // { "SPI", no_argument, NULL, 'p' },
82 // { "check-reachability", required_argument, NULL, 'r' },
83 // { "timeout", required_argument, NULL, 't' },
84 // { "wait-key", required_argument, NULL, 'w' },
85 { "get", required_argument
, NULL
, 0 },
86 { "help", no_argument
, NULL
, '?' },
87 { "set", required_argument
, NULL
, 0 },
93 getLine(char *buf
, int len
, InputRef src
)
101 line
= el_gets(src
->el
, &count
);
105 strncpy(buf
, line
, len
);
107 if (fgets(buf
, len
, src
->fp
) == NULL
)
112 if (buf
[n
-1] == '\n') {
113 /* the entire line fit in the buffer, remove the newline */
115 } else if (!src
->el
) {
116 /* eat the remainder of the line */
119 } while ((n
!= '\n') && (n
!= EOF
));
125 history(src
->h
, &ev
, H_ENTER
, buf
);
133 getString(char **line
)
135 char *s
, *e
, c
, *string
;
136 int i
, isQuoted
= 0, escaped
= 0;
138 if (*line
== NULL
) return NULL
;
139 if (**line
== '\0') return NULL
;
141 /* Skip leading white space */
142 while (isspace(**line
)) *line
+= 1;
144 /* Grab the next string */
147 return NULL
; /* no string available */
148 } else if (*s
== '"') {
149 isQuoted
= 1; /* it's a quoted string */
153 for (e
= s
; (c
= *e
) != '\0'; e
++) {
154 if (isQuoted
&& (c
== '"'))
155 break; /* end of quoted string */
159 break; /* if premature end-of-string */
160 if ((*e
== '"') || isspace(*e
))
161 escaped
++; /* if escaped quote or white space */
163 if (!isQuoted
&& isspace(c
))
164 break; /* end of non-quoted string */
167 string
= malloc(e
- s
- escaped
+ 1);
169 for (i
= 0; s
< e
; s
++) {
171 if (!((s
[0] == '\\') && ((s
[1] == '"') || isspace(s
[1])))) i
++;
176 e
++; /* move past end of quoted string */
184 process_line(InputRef src
)
186 char line
[LINE_LENGTH
], *s
, *arg
, **argv
= NULL
;
189 /* if end-of-file, exit */
190 if (getLine(line
, sizeof(line
), src
) == NULL
)
194 SCPrint(TRUE
, stdout
, CFSTR("%d> %s\n"), nesting
, line
);
197 /* if requested, exit */
198 if (strcasecmp(line
, "exit") == 0) return FALSE
;
199 if (strcasecmp(line
, "quit") == 0) return FALSE
;
200 if (strcasecmp(line
, "q" ) == 0) return FALSE
;
202 /* break up the input line */
205 while ((arg
= getString(&s
)) != NULL
) {
207 argv
= (char **)malloc(2 * sizeof(char *));
209 argv
= (char **)realloc(argv
, ((argc
+ 2) * sizeof(char *)));
213 /* process the command */
215 argv
[argc
] = NULL
; /* just in case... */
218 do_command(argc
, argv
);
220 for (i
= 0; i
< argc
; i
++)
230 usage(const char *command
)
232 SCPrint(TRUE
, stderr
, CFSTR("usage: %s\n"), command
);
233 SCPrint(TRUE
, stderr
, CFSTR("\tinteractive access to the dynamic store.\n"));
234 SCPrint(TRUE
, stderr
, CFSTR("\n"));
235 SCPrint(TRUE
, stderr
, CFSTR(" or: %s -r nodename\n"), command
);
236 SCPrint(TRUE
, stderr
, CFSTR(" or: %s -r address\n"), command
);
237 SCPrint(TRUE
, stderr
, CFSTR(" or: %s -r local-address remote-address\n"), command
);
238 SCPrint(TRUE
, stderr
, CFSTR("\tcheck reachability of node, address, or address pair.\n"));
239 SCPrint(TRUE
, stderr
, CFSTR("\n"));
240 SCPrint(TRUE
, stderr
, CFSTR(" or: %s -w dynamic-store-key [ -t timeout ]\n"), command
);
241 SCPrint(TRUE
, stderr
, CFSTR("\t-w\twait for presense of dynamic store key\n"));
242 SCPrint(TRUE
, stderr
, CFSTR("\t-t\ttime to wait for key\n"));
243 SCPrint(TRUE
, stderr
, CFSTR("\n"));
244 SCPrint(TRUE
, stderr
, CFSTR(" or: %s --get pref\n"), command
);
245 SCPrint(TRUE
, stderr
, CFSTR(" or: %s --set pref [newval]\n"), command
);
246 SCPrint(TRUE
, stderr
, CFSTR("\tpref\tdisplay (or set) the specified preference. Valid preferences\n"));
247 SCPrint(TRUE
, stderr
, CFSTR("\t\tinclude:\n"));
248 SCPrint(TRUE
, stderr
, CFSTR("\t\t\tComputerName, LocalHostName\n"));
249 SCPrint(TRUE
, stderr
, CFSTR("\tnewval\tNew preference value to be set. If not specified,\n"));
250 SCPrint(TRUE
, stderr
, CFSTR("\t\tthe new value will be read from standard input.\n"));
263 main(int argc
, char * const argv
[])
269 const char *prog
= argv
[0];
270 Boolean reach
= FALSE
;
273 int timeout
= 15; /* default timeout (in seconds) */
275 int xStore
= 0; /* non dynamic store command line options */
277 /* process any arguments */
279 while ((opt
= getopt_long(argc
, argv
, "dvprt:w:", longopts
, &opti
)) != -1)
283 _sc_log
= FALSE
; /* enable framework logging */
287 _sc_log
= FALSE
; /* enable framework logging */
290 enablePrivateAPI
= TRUE
;
297 timeout
= atoi(optarg
);
304 if (strcmp(longopts
[opti
].name
, "get") == 0) {
307 } else if (strcmp(longopts
[opti
].name
, "set") == 0) {
320 // if we are attempting to process more than one type of request
324 /* are we checking the reachability of a host/address */
326 if ((argc
< 1) || (argc
> 2)) {
329 do_checkReachability(argc
, (char **)argv
);
333 /* are we waiting on the presense of a dynamic store key */
335 do_wait(wait
, timeout
);
339 /* are we looking up a preference value */
341 if (findPref(get
) < 0) {
344 do_getPref(get
, argc
, (char **)argv
);
348 /* are we changing a preference value */
350 if (findPref(set
) < 0) {
353 do_setPref(set
, argc
, (char **)argv
);
357 /* start with an empty dictionary */
358 do_dictInit(0, NULL
);
360 /* allocate command input stream */
361 src
= (InputRef
)CFAllocatorAllocate(NULL
, sizeof(Input
), 0);
366 if (isatty(fileno(src
->fp
))) {
371 if (tcgetattr(fileno(src
->fp
), &t
) != -1) {
372 if ((t
.c_lflag
& ECHO
) == 0) {
376 src
->el
= el_init(prog
, src
->fp
, stdout
, stderr
);
377 src
->h
= history_init();
379 (void)history(src
->h
, &ev
, H_SETSIZE
, INT_MAX
);
380 el_set(src
->el
, EL_HIST
, history
, src
->h
);
383 el_set(src
->el
, EL_EDITMODE
, 0);
386 el_set(src
->el
, EL_EDITOR
, "emacs");
387 el_set(src
->el
, EL_PROMPT
, prompt
);
389 el_source(src
->el
, NULL
);
391 if ((el_get(src
->el
, EL_EDITMODE
, &editmode
) != -1) && editmode
!= 0) {
392 el_set(src
->el
, EL_SIGNAL
, 1);
401 while (process_line(src
) == TRUE
) {
402 /* debug information, diagnostics */
403 __showMachPortStatus();
406 /* close the socket, free resources */
407 if (src
->h
) history_end(src
->h
);
408 if (src
->el
) el_end(src
->el
);
409 (void)fclose(src
->fp
);
410 CFAllocatorDeallocate(NULL
, src
);
412 exit (EX_OK
); // insure the process exit status is 0
413 return 0; // ...and make main fit the ANSI spec.