#include <stdio.h>
#include <unistd.h>
#include <sys/fcntl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netat/appletalk.h>
#include <netat/at_var.h>
#include <AppleTalk/at_paths.h>
#include <AppleTalk/at_proto.h>
#include <SystemConfiguration/SystemConfiguration.h>
#include <SystemConfiguration/SCPrivate.h>
#include <SystemConfiguration/SCValidation.h>
#include "cfManager.h"
#define HOSTCONFIG "/etc/hostconfig"
SCDynamicStoreRef store = NULL;
CFRunLoopSourceRef rls = NULL;
CFMutableDictionaryRef oldGlobals = NULL;
CFMutableArrayRef oldConfigFile = NULL;
CFMutableDictionaryRef oldDefaults = NULL;
Boolean _verbose = FALSE;
static void
updateDefaults(const void *key, const void *val, void *context)
{
CFStringRef ifName = (CFStringRef)key;
CFDictionaryRef oldDict;
CFDictionaryRef newDict = (CFDictionaryRef)val;
CFNumberRef defaultNode;
CFNumberRef defaultNetwork;
CFStringRef defaultZone;
if (!CFDictionaryGetValueIfPresent(oldDefaults, ifName, (void **)&oldDict) ||
!CFEqual(oldDict, newDict)) {
char ifr_name[IFNAMSIZ];
bzero(&ifr_name, sizeof(ifr_name));
if (!CFStringGetCString(ifName, ifr_name, sizeof(ifr_name), kCFStringEncodingMacRoman)) {
SCLog(TRUE, LOG_ERR, CFSTR("CFStringGetCString: could not convert interface name to C string"));
return;
}
if (CFDictionaryGetValueIfPresent(newDict,
kSCPropNetAppleTalkNetworkID,
(void **)&defaultNetwork) &&
CFDictionaryGetValueIfPresent(newDict,
kSCPropNetAppleTalkNodeID,
(void **)&defaultNode)
) {
struct at_addr init_address;
int status;
CFNumberGetValue(defaultNetwork, kCFNumberShortType, &init_address.s_net);
CFNumberGetValue(defaultNode, kCFNumberCharType, &init_address.s_node);
status = at_setdefaultaddr(ifr_name, &init_address);
if (status == -1) {
SCLog(TRUE, LOG_ERR, CFSTR("at_setdefaultaddr() failed"));
}
}
if (CFDictionaryGetValueIfPresent(newDict,
kSCPropNetAppleTalkDefaultZone,
(void **)&defaultZone)
) {
at_nvestr_t zone;
bzero(&zone, sizeof(zone));
if (CFStringGetCString(defaultZone, zone.str, sizeof(zone.str), kCFStringEncodingMacRoman)) {
int status;
zone.len = strlen(zone.str);
status = at_setdefaultzone(ifr_name, &zone);
if (status == -1) {
SCLog(TRUE, LOG_ERR, CFSTR("at_setdefaultzone() failed"));
}
} else {
SCLog(TRUE, LOG_ERR, CFSTR("CFStringGetCString: could not convert default zone to C string"));
}
}
}
return;
}
static void
addZoneToPorts(const void *key, const void *val, void *context)
{
CFStringRef zone = (CFStringRef)key;
CFArrayRef ifArray = (CFArrayRef)val;
CFMutableArrayRef zones = (CFMutableArrayRef)context;
CFStringRef ifList;
CFStringRef configInfo;
ifList = CFStringCreateByCombiningStrings(NULL, ifArray, CFSTR(":"));
configInfo = CFStringCreateWithFormat(NULL, NULL, CFSTR(":%@:%@"), zone, ifList);
CFArrayAppendValue(zones, configInfo);
CFRelease(configInfo);
CFRelease(ifList);
return;
}
static CFStringRef
parse_component(CFStringRef key, CFStringRef prefix)
{
CFMutableStringRef comp;
CFRange range;
if (CFStringHasPrefix(key, prefix) == FALSE) {
return NULL;
}
comp = CFStringCreateMutableCopy(NULL, 0, key);
CFStringDelete(comp, CFRangeMake(0, CFStringGetLength(prefix)));
range = CFStringFind(comp, CFSTR("/"), 0);
if (range.location == kCFNotFound) {
return comp;
}
range.length = CFStringGetLength(comp) - range.location;
CFStringDelete(comp, range);
return comp;
}
static CFDictionaryRef
entity_one(SCDynamicStoreRef store, CFStringRef key)
{
CFDictionaryRef ent_dict = NULL;
CFDictionaryRef if_dict = NULL;
CFStringRef if_key = NULL;
CFStringRef if_port;
CFMutableDictionaryRef new_dict = NULL;
static CFStringRef pre = NULL;
CFStringRef serviceID = NULL;
CFStringRef serviceType;
if (!pre) {
pre = SCDynamicStoreKeyCreate(NULL,
CFSTR("%@/%@/%@/"),
kSCDynamicStoreDomainSetup,
kSCCompNetwork,
kSCCompService);
}
ent_dict = SCDynamicStoreCopyValue(store, key);
if (!isA_CFDictionary(ent_dict)) {
goto done;
}
serviceID = parse_component(key, pre);
if (!serviceID) {
goto done;
}
if_key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
kSCDynamicStoreDomainSetup,
serviceID,
kSCEntNetInterface);
if_dict = SCDynamicStoreCopyValue(store, if_key);
CFRelease(if_key);
if (!isA_CFDictionary(if_dict)) {
goto done;
}
serviceType = CFDictionaryGetValue(if_dict,
kSCPropNetInterfaceType);
if (!isA_CFString(serviceType) ||
!CFEqual(serviceType, kSCValNetInterfaceTypeEthernet)) {
goto done;
}
if_port = CFDictionaryGetValue(if_dict, kSCPropNetInterfaceDeviceName);
if (!isA_CFString(if_port)) {
goto done;
}
new_dict = CFDictionaryCreateMutableCopy(NULL, 0, ent_dict);
CFDictionarySetValue(new_dict, CFSTR("ServiceID"), serviceID);
CFDictionarySetValue(new_dict, kSCPropNetInterfaceDeviceName, if_port);
done:
if (ent_dict) CFRelease(ent_dict);
if (if_dict) CFRelease(if_dict);
if (serviceID) CFRelease(serviceID);
return (CFDictionaryRef)new_dict;
}
static CFArrayRef
entity_all(SCDynamicStoreRef store, CFStringRef entity, CFArrayRef order)
{
CFMutableArrayRef defined = NULL;
int i;
CFMutableArrayRef ordered = NULL;
CFStringRef pattern;
ordered = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
kSCDynamicStoreDomainSetup,
kSCCompAnyRegex,
entity);
defined = (CFMutableArrayRef)SCDynamicStoreCopyKeyList(store, pattern);
CFRelease(pattern);
if (defined && (CFArrayGetCount(defined) > 0)) {
CFArrayRef tmp;
tmp = defined;
defined = CFArrayCreateMutableCopy(NULL, 0, tmp);
CFRelease(tmp);
} else {
goto done;
}
for (i = 0; order && i < CFArrayGetCount(order); i++) {
CFDictionaryRef dict;
CFStringRef key;
CFIndex j;
CFStringRef service;
service = CFArrayGetValueAtIndex(order, i);
if (!isA_CFString(service)) {
continue;
}
key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
kSCDynamicStoreDomainSetup,
service,
entity);
dict = entity_one(store, key);
if (dict) {
CFArrayAppendValue(ordered, dict);
CFRelease(dict);
}
j = CFArrayGetFirstIndexOfValue(defined,
CFRangeMake(0, CFArrayGetCount(defined)),
key);
if (j >= 0) {
CFArrayRemoveValueAtIndex(defined, j);
}
CFRelease(key);
}
for (i = 0; i < CFArrayGetCount(defined); i++) {
CFDictionaryRef dict;
CFStringRef key;
key = CFArrayGetValueAtIndex(defined, i);
dict = entity_one(store, key);
if (dict) {
CFArrayAppendValue(ordered, dict);
CFRelease(dict);
}
}
done:
if (defined) CFRelease(defined);
if (CFArrayGetCount(ordered) == 0) {
CFRelease(ordered);
ordered = NULL;
}
return ordered;
}
static CFStringRef
encodeName(CFStringRef name, CFStringEncoding encoding)
{
CFDataRef bytes;
CFMutableStringRef encodedName = NULL;
CFIndex len;
if (!isA_CFString(name)) {
return NULL;
}
if (encoding == kCFStringEncodingMacRoman) {
return CFRetain(name);
}
bytes = CFStringCreateExternalRepresentation(NULL,
name,
encoding,
0);
if (bytes) {
unsigned char *byte;
CFIndex i;
encodedName = CFStringCreateMutable(NULL, 0);
len = CFDataGetLength(bytes);
byte = (unsigned char *)CFDataGetBytePtr(bytes);
for (i=0; i<len; i++, byte++) {
CFStringAppendFormat(encodedName,
NULL,
CFSTR("%02x"),
*byte);
}
CFStringInsert(encodedName, 0, CFSTR("*"));
CFStringAppend(encodedName, CFSTR("*"));
CFRelease(bytes);
}
return (CFStringRef)encodedName;
}
static boolean_t
updateConfiguration()
{
boolean_t changed = FALSE;
CFStringRef computerName;
CFStringEncoding computerNameEncoding;
CFArrayRef config;
CFArrayRef configuredInterfaces = NULL;
CFDictionaryRef dict;
CFIndex i;
CFIndex ifCount = 0;
CFStringRef key;
CFArrayRef keys;
CFMutableArrayRef newConfig;
CFMutableArrayRef newConfigFile;
CFMutableDictionaryRef newDefaults;
CFMutableDictionaryRef newDict;
CFMutableDictionaryRef newGlobals;
CFMutableDictionaryRef newState;
CFMutableDictionaryRef newZones;
CFNumberRef num;
CFStringRef primaryPort = NULL;
CFStringRef primaryZone = NULL;
CFArrayRef serviceOrder = NULL;
CFDictionaryRef setGlobals = NULL;
CFMutableArrayRef state = NULL;
CFStringRef str;
boolean_t useFlatFiles = TRUE;
if (useFlatFiles) {
key = SCDynamicStoreKeyCreate(NULL,
CFSTR("%@" "UseFlatFiles"),
kSCDynamicStoreDomainSetup);
dict = SCDynamicStoreCopyValue(store, key);
CFRelease(key);
if (dict) {
CFRelease(dict);
return FALSE;
}
useFlatFiles = FALSE;
}
newConfigFile = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
newGlobals = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
newDefaults = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
newState = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
newZones = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(newGlobals, CFSTR("APPLETALK"), CFSTR("-NO-"));
(void)SCDynamicStoreLock(store);
key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
kSCDynamicStoreDomainSetup,
kSCEntNetAppleTalk);
setGlobals = SCDynamicStoreCopyValue(store, key);
CFRelease(key);
if (setGlobals) {
if (isA_CFDictionary(setGlobals)) {
serviceOrder = CFDictionaryGetValue(setGlobals,
kSCPropNetServiceOrder);
serviceOrder = isA_CFArray(serviceOrder);
if (serviceOrder) {
CFRetain(serviceOrder);
}
} else {
CFRelease(setGlobals);
setGlobals = NULL;
}
}
if (!serviceOrder) {
key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
kSCDynamicStoreDomainSetup,
kSCEntNetIPv4);
dict = SCDynamicStoreCopyValue(store, key);
CFRelease(key);
if (dict) {
if (isA_CFDictionary(dict)) {
serviceOrder = CFDictionaryGetValue(dict,
kSCPropNetServiceOrder);
serviceOrder = isA_CFArray(serviceOrder);
if (serviceOrder) {
CFRetain(serviceOrder);
}
}
CFRelease(dict);
}
}
configuredInterfaces = entity_all(store, kSCEntNetAppleTalk, serviceOrder);
if (configuredInterfaces) {
ifCount = CFArrayGetCount(configuredInterfaces);
}
key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
kSCDynamicStoreDomainState,
kSCCompAnyRegex,
kSCEntNetAppleTalk);
keys = SCDynamicStoreCopyKeyList(store, key);
CFRelease(key);
if (keys) {
state = CFArrayCreateMutableCopy(NULL, 0, keys);
CFRelease(keys);
}
(void)SCDynamicStoreUnlock(store);
if (serviceOrder) CFRelease(serviceOrder);
for (i=0; i<ifCount; i++) {
CFDictionaryRef service;
CFStringRef ifName;
CFStringRef configMethod;
CFMutableStringRef portConfig = NULL;
CFArrayRef networkRange;
int sNetwork;
int eNetwork;
CFArrayRef zoneList;
CFIndex zCount;
CFIndex j;
CFMutableDictionaryRef ifDefaults = NULL;
CFNumberRef defaultNetwork;
CFNumberRef defaultNode;
CFStringRef defaultZone;
service = CFArrayGetValueAtIndex(configuredInterfaces, i);
ifName = CFDictionaryGetValue(service, kSCPropNetInterfaceDeviceName);
key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
kSCDynamicStoreDomainState,
ifName,
kSCEntNetLink);
dict = SCDynamicStoreCopyValue(store, key);
CFRelease(key);
if (dict) {
Boolean linkStatus = TRUE;
if (isA_CFDictionary(dict)) {
CFBooleanRef bool;
bool = CFDictionaryGetValue(dict, kSCPropNetLinkActive);
if (isA_CFBoolean(bool)) {
linkStatus = CFBooleanGetValue(bool);
}
}
CFRelease(dict);
if (!linkStatus) {
goto nextIF;
}
}
configMethod = CFDictionaryGetValue(service, kSCPropNetAppleTalkConfigMethod);
if (!isA_CFString(configMethod)) {
goto nextIF;
}
if (!CFEqual(configMethod, kSCValNetAppleTalkConfigMethodNode ) &&
!CFEqual(configMethod, kSCValNetAppleTalkConfigMethodRouter ) &&
!CFEqual(configMethod, kSCValNetAppleTalkConfigMethodSeedRouter)) {
SCLog(TRUE, LOG_NOTICE,
CFSTR("Unexpected AppleTalk ConfigMethod: %@"),
configMethod);
goto nextIF;
}
portConfig = CFStringCreateMutable(NULL, 0);
CFStringAppendFormat(portConfig, NULL, CFSTR("%@:"), ifName);
if (CFEqual(configMethod, kSCValNetAppleTalkConfigMethodSeedRouter)) {
CFNumberRef num;
networkRange = CFDictionaryGetValue(service,
kSCPropNetAppleTalkSeedNetworkRange);
if (!isA_CFArray(networkRange) || (CFArrayGetCount(networkRange) == 0)) {
SCLog(TRUE, LOG_NOTICE,
CFSTR("AppleTalk configuration error (%@)"),
kSCPropNetAppleTalkSeedNetworkRange);
goto nextIF;
}
num = CFArrayGetValueAtIndex(networkRange, 0);
if (!isA_CFNumber(num)) {
SCLog(TRUE, LOG_NOTICE,
CFSTR("AppleTalk configuration error (%@)"),
kSCPropNetAppleTalkSeedNetworkRange);
goto nextIF;
}
CFNumberGetValue(num, kCFNumberIntType, &sNetwork);
eNetwork = sNetwork;
if (CFArrayGetCount(networkRange) > 1) {
num = CFArrayGetValueAtIndex(networkRange, 1);
if (!isA_CFNumber(num)) {
SCLog(TRUE, LOG_NOTICE,
CFSTR("AppleTalk configuration error (%@)"),
kSCPropNetAppleTalkSeedNetworkRange);
goto nextIF;
}
CFNumberGetValue(num, kCFNumberIntType, &eNetwork);
}
CFStringAppendFormat(portConfig, NULL, CFSTR("%d:%d:"), sNetwork, eNetwork);
zoneList = CFDictionaryGetValue(service,
kSCPropNetAppleTalkSeedZones);
if (!isA_CFArray(zoneList)) {
SCLog(TRUE, LOG_NOTICE,
CFSTR("AppleTalk configuration error (%@)"),
kSCPropNetAppleTalkSeedZones);
goto nextIF;
}
zCount = CFArrayGetCount(zoneList);
for (j=0; j<zCount; j++) {
CFStringRef zone;
CFArrayRef ifList;
CFMutableArrayRef newIFList;
zone = CFArrayGetValueAtIndex(zoneList, j);
if (!isA_CFString(zone)) {
continue;
}
if (CFDictionaryGetValueIfPresent(newZones, zone, (void **)&ifList)) {
newIFList = CFArrayCreateMutableCopy(NULL, 0, ifList);
} else {
newIFList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
}
CFArrayAppendValue(newIFList, ifName);
CFArraySortValues(newIFList,
CFRangeMake(0, CFArrayGetCount(newIFList)),
(CFComparatorFunction)CFStringCompare,
NULL);
CFDictionarySetValue(newZones, zone, newIFList);
CFRelease(newIFList);
if (!primaryZone) {
primaryZone = CFRetain(zone);
}
}
if (!primaryZone) {
SCLog(TRUE, LOG_NOTICE,
CFSTR("AppleTalk configuration error (%@)"),
kSCPropNetAppleTalkSeedZones);
goto nextIF;
}
}
computerName = CFDictionaryGetValue(service,
kSCPropNetAppleTalkComputerName);
if (CFDictionaryGetValueIfPresent(service,
kSCPropNetAppleTalkComputerNameEncoding,
(void **)&num) &&
isA_CFNumber(num)) {
CFNumberGetValue(num, kCFNumberIntType, &computerNameEncoding);
} else {
computerNameEncoding = CFStringGetSystemEncoding();
}
str = encodeName(computerName, computerNameEncoding);
if (str) {
CFDictionaryAddValue(newGlobals,
CFSTR("APPLETALK_HOSTNAME"),
str);
CFRelease(str);
}
if (CFArrayGetCount(newConfigFile) == 0) {
CFStringAppend(portConfig, CFSTR("*"));
primaryPort = CFRetain(ifName);
}
CFArrayAppendValue(newConfigFile, portConfig);
ifDefaults = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
defaultNetwork = CFDictionaryGetValue(service, kSCPropNetAppleTalkNetworkID);
defaultNode = CFDictionaryGetValue(service, kSCPropNetAppleTalkNodeID);
if (isA_CFNumber(defaultNetwork) && isA_CFNumber(defaultNode)) {
CFDictionarySetValue(ifDefaults,
kSCPropNetAppleTalkNetworkID,
defaultNetwork);
CFDictionarySetValue(ifDefaults,
kSCPropNetAppleTalkNodeID,
defaultNode);
}
if ((CFDictionaryGetValueIfPresent(service,
kSCPropNetAppleTalkDefaultZone,
(void **)&defaultZone) == TRUE)) {
CFDictionarySetValue(ifDefaults,
kSCPropNetAppleTalkDefaultZone,
defaultZone);
}
CFDictionarySetValue(newDefaults, ifName, ifDefaults);
CFRelease(ifDefaults);
switch (CFArrayGetCount(newConfigFile)) {
case 1:
CFDictionarySetValue(newGlobals, CFSTR("APPLETALK"), ifName);
break;
case 2:
if (!CFEqual(CFDictionaryGetValue(newGlobals, CFSTR("APPLETALK")),
CFSTR("-ROUTER-"))) {
CFDictionarySetValue(newGlobals, CFSTR("APPLETALK"), CFSTR("-MULTIHOME-"));
}
break;
}
if (CFEqual(configMethod, kSCValNetAppleTalkConfigMethodRouter) ||
CFEqual(configMethod, kSCValNetAppleTalkConfigMethodSeedRouter)) {
CFDictionarySetValue(newGlobals, CFSTR("APPLETALK"), CFSTR("-ROUTER-"));
}
key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
kSCDynamicStoreDomainState,
CFDictionaryGetValue(service, CFSTR("ServiceID")),
kSCEntNetAppleTalk);
newDict = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFDictionaryAddValue(newDict, kSCPropInterfaceName, ifName);
CFDictionaryAddValue(newState, key, newDict);
CFRelease(newDict);
if (state) {
j = CFArrayGetFirstIndexOfValue(state,
CFRangeMake(0, CFArrayGetCount(state)),
key);
if (j != kCFNotFound) {
CFArrayRemoveValueAtIndex(state, j);
}
}
CFRelease(key);
nextIF :
if (portConfig) CFRelease(portConfig);
}
if (primaryZone) {
CFArrayRef ifList;
CFMutableArrayRef newIFList;
ifList = CFDictionaryGetValue(newZones, primaryZone);
if (CFArrayContainsValue(ifList,
CFRangeMake(0, CFArrayGetCount(ifList)),
primaryPort)) {
newIFList = CFArrayCreateMutableCopy(NULL, 0, ifList);
CFArrayAppendValue(newIFList, CFSTR("*"));
CFDictionarySetValue(newZones, primaryZone, newIFList);
CFRelease(newIFList);
}
CFRelease(primaryZone);
}
if (primaryPort) {
CFRelease(primaryPort);
}
i = CFArrayGetCount(newConfigFile);
CFArraySortValues(newConfigFile,
CFRangeMake(0, i),
(CFComparatorFunction)CFStringCompare,
NULL);
CFDictionaryApplyFunction(newZones, addZoneToPorts, newConfigFile);
CFRelease(newZones);
CFArraySortValues(newConfigFile,
CFRangeMake(i, CFArrayGetCount(newConfigFile)-i),
(CFComparatorFunction)CFStringCompare,
NULL);
CFArrayAppendValue(newConfigFile, CFSTR(""));
if (!CFDictionaryContainsKey(newGlobals, CFSTR("APPLETALK_HOSTNAME")) &&
(setGlobals != NULL)) {
computerName = CFDictionaryGetValue(setGlobals,
kSCPropNetAppleTalkComputerName);
if (CFDictionaryGetValueIfPresent(setGlobals,
kSCPropNetAppleTalkComputerNameEncoding,
(void **)&num) &&
isA_CFNumber(num)) {
CFNumberGetValue(num, kCFNumberIntType, &computerNameEncoding);
} else {
computerNameEncoding = CFStringGetSystemEncoding();
}
str = encodeName(computerName, computerNameEncoding);
if (str) {
CFDictionaryAddValue(newGlobals,
CFSTR("APPLETALK_HOSTNAME"),
str);
CFRelease(str);
}
}
if (!CFDictionaryContainsKey(newGlobals, CFSTR("APPLETALK_HOSTNAME"))) {
computerName = SCDynamicStoreCopyComputerName(store, &computerNameEncoding);
if (computerName) {
str = encodeName(computerName, computerNameEncoding);
if (str) {
CFDictionaryAddValue(newGlobals,
CFSTR("APPLETALK_HOSTNAME"),
str);
CFRelease(str);
}
CFRelease(computerName);
}
}
config = configRead(HOSTCONFIG);
newConfig = CFArrayCreateMutableCopy(NULL, 0, config);
configSet(newConfig,
CFSTR("APPLETALK"),
CFDictionaryGetValue(newGlobals, CFSTR("APPLETALK")));
if (CFDictionaryGetValueIfPresent(newGlobals,
CFSTR("APPLETALK_HOSTNAME"),
(void *)&computerName)) {
configSet (newConfig, CFSTR("APPLETALK_HOSTNAME"), computerName);
} else {
configRemove(newConfig, CFSTR("APPLETALK_HOSTNAME"));
}
if (CFEqual(oldGlobals , newGlobals ) &&
CFEqual(oldConfigFile , newConfigFile) &&
CFEqual(oldDefaults , newDefaults )
) {
CFRelease(newGlobals);
CFRelease(newConfigFile);
CFRelease(newDefaults);
} else if (CFArrayGetCount(newConfigFile) <= 1) {
configRemove(newConfig, CFSTR("APPLETALK_HOSTNAME"));
(void)unlink(AT_CFG_FILE);
changed = TRUE;
} else {
configWrite(AT_CFG_FILE, newConfigFile);
CFDictionaryApplyFunction(newDefaults, updateDefaults, NULL);
changed = TRUE;
}
if (changed) {
if (!SCDynamicStoreSetMultiple(store, newState, state, NULL)) {
SCLog(TRUE,
LOG_ERR,
CFSTR("SCDynamicStoreSetMultiple() failed: %s"),
SCErrorString(SCError()));
}
}
if (state) CFRelease(state);
if (newState) CFRelease(newState);
if (changed) {
CFRelease(oldGlobals);
oldGlobals = newGlobals;
CFRelease(oldConfigFile);
oldConfigFile = newConfigFile;
CFRelease(oldDefaults);
oldDefaults = newDefaults;
}
if (!CFEqual(config, newConfig)) {
configWrite(HOSTCONFIG, newConfig);
changed = TRUE;
}
CFRelease(config);
CFRelease(newConfig);
if (configuredInterfaces)
CFRelease(configuredInterfaces);
if (setGlobals) CFRelease(setGlobals);
return changed;
}
static void
atConfigChangedCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *arg)
{
boolean_t configChanged;
static boolean_t initialConfiguration = TRUE;
CFStringRef key;
configChanged = updateConfiguration();
if (initialConfiguration) {
initialConfiguration = FALSE;
(void) SCDynamicStoreRemoveWatchedKey(store, kSCDynamicStoreDomainSetup, FALSE);
} else if (configChanged) {
key = SCDynamicStoreKeyCreate(NULL,
CFSTR("%@%s"),
kSCDynamicStoreDomainFile,
AT_CFG_FILE);
if (!SCDynamicStoreNotifyValue(store, key)) {
SCLog(TRUE,
LOG_ERR,
CFSTR("SCDynamicStoreNotifyValue() failed: %s"),
SCErrorString(SCError()));
}
CFRelease(key);
}
key = SCDynamicStoreKeyCreate(NULL,
CFSTR("%@%@"),
kSCDynamicStoreDomainPlugin,
kSCEntNetAppleTalk);
if (!SCDynamicStoreNotifyValue(store, key)) {
SCLog(TRUE,
LOG_ERR,
CFSTR("SCDynamicStoreNotifyValue() failed: %s"),
SCErrorString(SCError()));
}
CFRelease(key);
return;
}
void
load(CFBundleRef bundle, Boolean bundleVerbose)
{
CFStringRef key;
CFMutableArrayRef keys = NULL;
CFMutableArrayRef patterns = NULL;
if (bundleVerbose) {
_verbose = TRUE;
}
SCLog(_verbose, LOG_DEBUG, CFSTR("load() called"));
SCLog(_verbose, LOG_DEBUG, CFSTR(" bundle ID = %@"), CFBundleGetIdentifier(bundle));
oldGlobals = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
oldConfigFile = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
oldDefaults = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
store = SCDynamicStoreCreate(NULL,
CFSTR("AppleTalk Configuraton plug-in"),
atConfigChangedCallback,
NULL);
if (!store) {
SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreCreate() failed: %s"), SCErrorString(SCError()));
goto error;
}
keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
CFArrayAppendValue(keys, kSCDynamicStoreDomainSetup);
key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
kSCDynamicStoreDomainSetup,
kSCEntNetAppleTalk);
CFArrayAppendValue(patterns, key);
CFRelease(key);
key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
kSCDynamicStoreDomainSetup,
kSCCompAnyRegex,
kSCEntNetAppleTalk);
CFArrayAppendValue(patterns, key);
CFRelease(key);
key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
kSCDynamicStoreDomainState,
kSCCompAnyRegex,
kSCEntNetLink);
CFArrayAppendValue(patterns, key);
CFRelease(key);
key = SCDynamicStoreKeyCreateComputerName(NULL);
CFArrayAppendValue(keys, key);
CFRelease(key);
if (!SCDynamicStoreSetNotificationKeys(store, keys, patterns)) {
SCLog(TRUE, LOG_ERR,
CFSTR("SCDynamicStoreSetNotificationKeys() failed: %s"),
SCErrorString(SCError()));
goto error;
}
rls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
if (!rls) {
SCLog(TRUE, LOG_ERR,
CFSTR("SCDynamicStoreCreateRunLoopSource() failed: %s"),
SCErrorString(SCError()));
goto error;
}
CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
CFRelease(keys);
CFRelease(patterns);
return;
error :
if (oldGlobals) CFRelease(oldGlobals);
if (oldConfigFile) CFRelease(oldConfigFile);
if (oldDefaults) CFRelease(oldDefaults);
if (store) CFRelease(store);
if (keys) CFRelease(keys);
if (patterns) CFRelease(patterns);
return;
}
#ifdef MAIN
#include "cfManager.c"
int
main(int argc, char **argv)
{
_sc_log = FALSE;
_sc_verbose = (argc > 1) ? TRUE : FALSE;
load(CFBundleGetMainBundle(), (argc > 1) ? TRUE : FALSE);
CFRunLoopRun();
exit(0);
return 0;
}
#endif