#include <SystemConfiguration/SystemConfiguration.h>
#include <unistd.h>
boolean_t apply = TRUE;
void
usage(const char *command)
{
SCDLog(LOG_ERR, CFSTR("usage: %s [-n] new-set-name"), command);
return;
}
int
main(int argc, char **argv)
{
const char *command = argv[0];
extern int optind;
int opt;
CFStringRef current = NULL;
int currentMatched = 0;
CFStringRef newSet = NULL;
CFStringRef newSetUDN = NULL;
CFStringRef prefix;
SCPStatus status;
SCPSessionRef session;
CFDictionaryRef sets;
CFIndex nSets;
void **setKeys;
void **setVals;
CFIndex i;
SCDOptionSet(NULL, kSCDOptionUseSyslog, FALSE);
while ((opt = getopt(argc, argv, "dvn")) != -1)
switch(opt) {
case 'd':
SCDOptionSet(NULL, kSCDOptionDebug, TRUE);
break;
case 'v':
SCDOptionSet(NULL, kSCDOptionVerbose, TRUE);
break;
case 'n':
apply = FALSE;
break;
case '?':
default :
usage(command);
}
argc -= optind;
argv += optind;
prefix = CFStringCreateWithFormat(NULL, NULL, CFSTR("/%@/"), kSCPrefSets);
newSet = (argc == 1)
? CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingMacRoman)
: CFSTR("");
status = SCPOpen(&session, CFSTR("Select Set Command"), NULL, 0);
if (status != SCP_OK) {
SCDLog(LOG_ERR,
CFSTR("SCPOpen() failed: %s"),
SCPError(status));
exit (1);
}
if ((CFStringGetLength(newSet) > 0) && CFStringHasPrefix(newSet, prefix)) {
CFRange range;
CFMutableStringRef str;
str = CFStringCreateMutableCopy(NULL, 0, newSet);
CFStringDelete(str, CFRangeMake(0, CFStringGetLength(prefix)));
range = CFStringFind(str, CFSTR("/"), 0);
if (range.location != kCFNotFound) {
SCDLog(LOG_ERR, CFSTR("Set \"%@\" not available."), newSet);
exit (1);
}
CFRelease(newSet);
newSet = str;
}
status = SCPGet(session, kSCPrefSets, (CFPropertyListRef *)&sets);
if (status != SCP_OK) {
SCDLog(LOG_ERR, CFSTR("SCDGet(...,%s,...) failed: %s"), SCPError(status));
exit (1);
}
status = SCPGet(session, kSCPrefCurrentSet, (CFPropertyListRef *)¤t);
switch (status) {
case SCP_OK :
if (CFStringHasPrefix(current, prefix)) {
CFMutableStringRef tmp;
tmp = CFStringCreateMutableCopy(NULL, 0, current);
CFStringDelete(tmp, CFRangeMake(0, CFStringGetLength(prefix)));
current = tmp;
} else {
currentMatched = -1;
}
break;
case SCP_NOKEY :
current = CFSTR("");
currentMatched = -2;
break;
default :
SCDLog(LOG_ERR, CFSTR("SCDGet(...,%s,...) failed: %s"), SCPError(status));
exit (1);
}
nSets = CFDictionaryGetCount(sets);
setKeys = CFAllocatorAllocate(NULL, nSets * sizeof(CFStringRef), 0);
setVals = CFAllocatorAllocate(NULL, nSets * sizeof(CFDictionaryRef), 0);
CFDictionaryGetKeysAndValues(sets, setKeys, setVals);
for (i=0; i<nSets; i++) {
CFStringRef key = (CFStringRef) setKeys[i];
CFDictionaryRef dict = (CFDictionaryRef)setVals[i];
if ((currentMatched >= 0) && CFEqual(key, current)) {
currentMatched++;
}
if (CFEqual(newSet, key)) {
newSetUDN = CFDictionaryGetValue(dict, kSCPropUserDefinedName);
if (newSetUDN) CFRetain(newSetUDN);
current = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), prefix, newSet);
goto found;
}
}
for (i=0; i<nSets; i++) {
CFStringRef key = (CFStringRef) setKeys[i];
CFDictionaryRef dict = (CFDictionaryRef)setVals[i];
newSetUDN = CFDictionaryGetValue(dict, kSCPropUserDefinedName);
if ((newSetUDN != NULL) && CFEqual(newSet, newSetUDN)) {
CFRelease(newSet);
newSet = CFRetain(key);
CFRetain(newSetUDN);
current = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), prefix, newSet);
goto found;
}
}
if (argc == 2) {
SCDLog(LOG_ERR, CFSTR("Set \"%@\" not available."), newSet);
} else {
usage(command);
}
SCDLog(LOG_ERR, CFSTR(""));
SCDLog(LOG_ERR,
CFSTR("Defined sets include:%s"),
(currentMatched > 0) ? " (* == current set)" : "");
for (i=0; i<nSets; i++) {
CFStringRef key = (CFStringRef) setKeys[i];
CFDictionaryRef dict = (CFDictionaryRef)setVals[i];
CFStringRef udn = CFDictionaryGetValue(dict, kSCPropUserDefinedName);
SCDLog(LOG_ERR,
CFSTR(" %s %@\t(%@)"),
((currentMatched > 0) && CFEqual(key, current)) ? "*" : " ",
key,
udn ? udn : CFSTR(""));
}
switch (currentMatched) {
case -2 :
SCDLog(LOG_ERR, CFSTR(""));
SCDLog(LOG_ERR, CFSTR("CurrentSet not defined"));
break;
case -1 :
SCDLog(LOG_ERR, CFSTR(""));
SCDLog(LOG_ERR, CFSTR("CurrentSet \"%@\" may not be valid"), current);
break;
case 0 :
SCDLog(LOG_ERR, CFSTR(""));
SCDLog(LOG_ERR, CFSTR("CurrentSet \"%@\" not valid"), current);
break;
default :
break;
}
exit (1);
found :
status = SCPSet(session, kSCPrefCurrentSet, current);
if (status != SCP_OK) {
SCDLog(LOG_ERR,
CFSTR("SCDSet(...,%@,%@) failed: %s"),
kSCPrefCurrentSet,
current,
SCPError(status));
exit (1);
}
status = SCPCommit(session);
if (status != SCP_OK) {
SCDLog(LOG_ERR, CFSTR("SCPCommit() failed: %s"), SCPError(status));
exit (1);
}
if (apply) {
status = SCPApply(session);
if (status != SCP_OK) {
SCDLog(LOG_ERR, CFSTR("SCPApply() failed: %s"), SCPError(status));
exit (1);
}
}
status = SCPClose(&session);
if (status != SCP_OK) {
SCDLog(LOG_ERR, CFSTR("SCPClose() failed: %s"), SCPError(status));
exit (1);
}
SCDLog(LOG_NOTICE,
CFSTR("%@ updated to %@ (%@)"),
kSCPrefCurrentSet,
newSet,
newSetUDN ? newSetUDN : CFSTR(""));
exit (0);
return 0;
}