#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sysexits.h>
#ifdef DEBUG
#include <mach/mach.h>
#include <mach/mach_error.h>
#endif
#include "scutil.h"
#include "commands.h"
#include "dictionary.h"
#include "tests.h"
#include <SystemConfiguration/SCPrivate.h>
#include "SCDynamicStoreInternal.h"
#define LINE_LENGTH 256
int nesting = 0;
CFRunLoopSourceRef notifyRls = NULL;
CFMutableArrayRef sources = NULL;
SCDynamicStoreRef store = NULL;
CFPropertyListRef value = NULL;
static char *
getLine(char *buf, int len, FILE *fp)
{
int x;
if (fgets(buf, len, fp) == NULL)
return NULL;
x = strlen(buf);
if (buf[x-1] == '\n') {
buf[x-1] = '\0';
} else {
do {
x = fgetc(fp);
} while ((x != '\n') && (x != EOF));
}
return buf;
}
char *
getString(char **line)
{
char *s, *e, c, *string;
int i, isQuoted = 0, escaped = 0;
if (*line == NULL) return NULL;
if (**line == '\0') return NULL;
while (isspace(**line)) *line += 1;
s = *line;
if (*s == '\0') {
return NULL;
} else if (*s == '"') {
isQuoted = 1;
s++;
}
for (e = s; (c = *e) != '\0'; e++) {
if (isQuoted && (c == '"'))
break;
if (c == '\\') {
e++;
if (*e == '\0')
break;
if ((*e == '"') || isspace(*e))
escaped++;
}
if (!isQuoted && isspace(c))
break;
}
string = malloc(e - s - escaped + 1);
for (i = 0; s < e; s++) {
string[i] = *s;
if (!((s[0] == '\\') && ((s[1] == '"') || isspace(s[1])))) i++;
}
string[i] = '\0';
if (isQuoted)
e++;
*line = e;
return string;
}
Boolean
process_line(FILE *fp)
{
char line[LINE_LENGTH], *s, *arg, **argv = NULL;
int i, argc;
if (getLine(line, sizeof(line), fp) == NULL)
return FALSE;
if (nesting > 0) {
SCPrint(TRUE, stdout, CFSTR("%d> %s\n"), nesting, line);
}
if (strcasecmp(line, "exit") == 0) return FALSE;
if (strcasecmp(line, "quit") == 0) return FALSE;
if (strcasecmp(line, "q" ) == 0) return FALSE;
s = line;
argc = 0;
while ((arg = getString(&s)) != NULL) {
if (argc == 0)
argv = (char **)malloc(2 * sizeof(char *));
else
argv = (char **)realloc(argv, ((argc + 2) * sizeof(char *)));
argv[argc++] = arg;
}
if (argc > 0) {
argv[argc] = NULL;
if (*argv[0] != '#')
do_command(argc, argv);
for (i = 0; i < argc; i++)
free(argv[i]);
free(argv);
}
return TRUE;
}
void
runLoopProcessInput(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info)
{
FILE *fp = info;
if (process_line(fp) == FALSE) {
CFRunLoopRemoveSource(CFRunLoopGetCurrent(),
(CFRunLoopSourceRef)CFArrayGetValueAtIndex(sources, 0),
kCFRunLoopDefaultMode);
CFSocketInvalidate(s);
CFArrayRemoveValueAtIndex(sources, 0);
if (CFArrayGetCount(sources) > 0) {
CFRunLoopAddSource(CFRunLoopGetCurrent(),
(CFRunLoopSourceRef)CFArrayGetValueAtIndex(sources, 0),
kCFRunLoopDefaultMode);
} else {
exit (EX_OK);
}
nesting--;
}
__showMachPortStatus();
if ((CFArrayGetCount(sources) == 1) && isatty(STDIN_FILENO)) {
printf("> ");
fflush(stdout);
}
return;
}
void
usage(const char *command)
{
SCPrint(TRUE, stderr, CFSTR("usage: %s\n"), command);
SCPrint(TRUE, stderr, CFSTR(" or: %s -r node-or-address\n"), command);
SCPrint(TRUE, stderr, CFSTR("\t-r\tcheck reachability of node/address\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("Note: you may only specify one of \"-r\" or \"-w\".\n"));
exit (EX_USAGE);
}
int
main(int argc, char * const argv[])
{
CFSocketContext context = { 0, stdin, NULL, NULL, NULL };
char *dest = NULL;
CFSocketRef in;
extern int optind;
int opt;
const char *prog = argv[0];
CFRunLoopSourceRef rls;
int timeout = 15;
char *wait = NULL;
while ((opt = getopt(argc, argv, "dvpr:t:w:")) != -1)
switch(opt) {
case 'd':
_sc_debug = TRUE;
_sc_log = FALSE;
break;
case 'v':
_sc_verbose = TRUE;
_sc_log = FALSE;
break;
case 'p':
enablePrivateAPI = TRUE;
break;
case 'r':
dest = optarg;
break;
case 't':
timeout = atoi(optarg);
break;
case 'w':
wait = optarg;
break;
case '?':
default :
usage(prog);
}
argc -= optind;
argv += optind;
if (dest && wait) {
usage(prog);
}
if (dest) {
do_checkReachability(dest);
}
if (wait) {
do_wait(wait, timeout);
}
do_dictInit(0, NULL);
in = CFSocketCreateWithNative(NULL,
STDIN_FILENO,
kCFSocketReadCallBack,
runLoopProcessInput,
&context);
rls = CFSocketCreateRunLoopSource(NULL, in, nesting);
sources = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
CFArrayAppendValue(sources, rls);
CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
CFRelease(rls);
CFRelease(in);
__showMachPortStatus();
if (isatty(STDIN_FILENO)) {
printf("> ");
fflush(stdout);
}
CFRunLoopRun();
exit (EX_OK); return 0; }