2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
24 * Modification History
26 * July 9, 2001 Allan Nathanson <ajn@apple.com>
27 * - added "-r" option for checking network reachability
28 * - added "-w" option to check/wait for the presence of a
31 * June 1, 2001 Allan Nathanson <ajn@apple.com>
32 * - public API conversion
34 * November 9, 2000 Allan Nathanson <ajn@apple.com>
46 #include <mach/mach.h>
47 #include <mach/mach_error.h>
52 #include "dictionary.h"
55 #include <SystemConfiguration/SCPrivate.h>
56 #include "SCDynamicStoreInternal.h"
59 #define LINE_LENGTH 256
63 CFRunLoopSourceRef notifyRls
= NULL
;
64 CFMutableArrayRef sources
= NULL
;
65 SCDynamicStoreRef store
= NULL
;
66 CFPropertyListRef value
= NULL
;
70 getLine(char *buf
, int len
, FILE *fp
)
74 if (fgets(buf
, len
, fp
) == NULL
)
78 if (buf
[x
-1] == '\n') {
79 /* the entire line fit in the buffer, remove the newline */
82 /* eat the remainder of the line */
85 } while ((x
!= '\n') && (x
!= EOF
));
93 getString(char **line
)
95 char *s
, *e
, c
, *string
;
96 int i
, isQuoted
= 0, escaped
= 0;
98 if (*line
== NULL
) return NULL
;
99 if (**line
== '\0') return NULL
;
101 /* Skip leading white space */
102 while (isspace(**line
)) *line
+= 1;
104 /* Grab the next string */
107 return NULL
; /* no string available */
108 } else if (*s
== '"') {
109 isQuoted
= 1; /* it's a quoted string */
113 for (e
= s
; (c
= *e
) != '\0'; e
++) {
114 if (isQuoted
&& (c
== '"'))
115 break; /* end of quoted string */
119 break; /* if premature end-of-string */
120 if ((*e
== '"') || isspace(*e
))
121 escaped
++; /* if escaped quote or white space */
123 if (!isQuoted
&& isspace(c
))
124 break; /* end of non-quoted string */
127 string
= malloc(e
- s
- escaped
+ 1);
129 for (i
= 0; s
< e
; s
++) {
131 if (!((s
[0] == '\\') && ((s
[1] == '"') || isspace(s
[1])))) i
++;
136 e
++; /* move past end of quoted string */
144 process_line(FILE *fp
)
146 char line
[LINE_LENGTH
], *s
, *arg
, **argv
= NULL
;
149 /* if end-of-file, exit */
150 if (getLine(line
, sizeof(line
), fp
) == NULL
)
154 SCPrint(TRUE
, stdout
, CFSTR("%d> %s\n"), nesting
, line
);
157 /* if requested, exit */
158 if (strcasecmp(line
, "exit") == 0) return FALSE
;
159 if (strcasecmp(line
, "quit") == 0) return FALSE
;
160 if (strcasecmp(line
, "q" ) == 0) return FALSE
;
162 /* break up the input line */
165 while ((arg
= getString(&s
)) != NULL
) {
167 argv
= (char **)malloc(2 * sizeof(char *));
169 argv
= (char **)realloc(argv
, ((argc
+ 2) * sizeof(char *)));
173 /* process the command */
175 argv
[argc
] = NULL
; /* just in case... */
178 do_command(argc
, argv
);
180 for (i
= 0; i
< argc
; i
++)
190 runLoopProcessInput(CFSocketRef s
, CFSocketCallBackType type
, CFDataRef address
, const void *data
, void *info
)
194 if (process_line(fp
) == FALSE
) {
195 /* we don't want any more input from this stream, stop listening */
196 CFRunLoopRemoveSource(CFRunLoopGetCurrent(),
197 (CFRunLoopSourceRef
)CFArrayGetValueAtIndex(sources
, 0),
198 kCFRunLoopDefaultMode
);
200 /* we no longer need the fd (socket) */
201 CFSocketInvalidate(s
);
203 /* we no longer need to track this source */
204 CFArrayRemoveValueAtIndex(sources
, 0);
206 if (CFArrayGetCount(sources
) > 0) {
207 /* add the previous input source to the run loop */
208 CFRunLoopAddSource(CFRunLoopGetCurrent(),
209 (CFRunLoopSourceRef
)CFArrayGetValueAtIndex(sources
, 0),
210 kCFRunLoopDefaultMode
);
212 /* no more input sources, we're done! */
216 /* decrement the nesting level */
220 /* debug information, diagnostics */
221 __showMachPortStatus();
223 /* if necessary, re-issue prompt */
224 if ((CFArrayGetCount(sources
) == 1) && isatty(STDIN_FILENO
)) {
234 usage(const char *command
)
236 SCPrint(TRUE
, stderr
, CFSTR("usage: %s\n"), command
);
237 SCPrint(TRUE
, stderr
, CFSTR(" or: %s -r node-or-address\n"), command
);
238 SCPrint(TRUE
, stderr
, CFSTR("\t-r\tcheck reachability of node/address\n"));
239 SCPrint(TRUE
, stderr
, CFSTR(" or: %s -w dynamic-store-key [ -t timeout ]\n"), command
);
240 SCPrint(TRUE
, stderr
, CFSTR("\t-w\twait for presense of dynamic store key\n"));
241 SCPrint(TRUE
, stderr
, CFSTR("\t-t\ttime to wait for key\n"));
242 SCPrint(TRUE
, stderr
, CFSTR("\n"));
243 SCPrint(TRUE
, stderr
, CFSTR("Note: you may only specify one of \"-r\" or \"-w\".\n"));
249 main(int argc
, char * const argv
[])
251 CFSocketContext context
= { 0, stdin
, NULL
, NULL
, NULL
};
256 const char *prog
= argv
[0];
257 CFRunLoopSourceRef rls
;
258 int timeout
= 15; /* default timeout (in seconds) */
261 /* process any arguments */
263 while ((opt
= getopt(argc
, argv
, "dvpr:t:w:")) != -1)
267 _sc_log
= FALSE
; /* enable framework logging */
271 _sc_log
= FALSE
; /* enable framework logging */
274 enablePrivateAPI
= TRUE
;
280 timeout
= atoi(optarg
);
296 /* are we checking the reachability of a host/address */
298 do_checkReachability(dest
);
302 /* are we waiting on the presense of a dynamic store key */
304 do_wait(wait
, timeout
);
308 /* start with an empty dictionary */
309 do_dictInit(0, NULL
);
311 /* create a "socket" reference with the file descriptor associated with stdin */
312 in
= CFSocketCreateWithNative(NULL
,
314 kCFSocketReadCallBack
,
318 /* Create a run loop source for the (stdin) file descriptor */
319 rls
= CFSocketCreateRunLoopSource(NULL
, in
, nesting
);
321 /* keep track of input file sources */
322 sources
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
323 CFArrayAppendValue(sources
, rls
);
325 /* add this source to the run loop */
326 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls
, kCFRunLoopDefaultMode
);
330 /* show (initial) debug information, diagnostics */
331 __showMachPortStatus();
333 /* issue (initial) prompt */
334 if (isatty(STDIN_FILENO
)) {
339 CFRunLoopRun(); /* process input, process events */
341 exit (EX_OK
); // insure the process exit status is 0
342 return 0; // ...and make main fit the ANSI spec.