#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>
#define SYSTEMCONFIGURATION_NEW_API
#include <SystemConfiguration/SystemConfiguration.h>
#include "cfManager.h"
#define HOSTCONFIG "/etc/hostconfig"
SCDSessionRef session = NULL;
CFMutableDictionaryRef oldGlobals = NULL;
CFMutableArrayRef oldConfigFile = NULL;
CFMutableDictionaryRef oldDefaults = NULL;
static __inline__ CFTypeRef
isA_CFType(CFTypeRef obj, CFTypeID type)
{
if (obj == NULL)
return (NULL);
if (CFGetTypeID(obj) != type)
return (NULL);
return (obj);
}
static __inline__ CFTypeRef
isA_CFDictionary(CFTypeRef obj)
{
return (isA_CFType(obj, CFDictionaryGetTypeID()));
}
static __inline__ CFTypeRef
isA_CFArray(CFTypeRef obj)
{
return (isA_CFType(obj, CFArrayGetTypeID()));
}
static __inline__ CFTypeRef
isA_CFString(CFTypeRef obj)
{
return (isA_CFType(obj, CFStringGetTypeID()));
}
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)) {
SCDLog(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) {
SCDLog(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) {
SCDLog(LOG_ERR, CFSTR("at_setdefaultzone() failed"));
}
} else {
SCDLog(LOG_ERR, CFSTR("CFStringGetCString: could not convert default zone to C string"));
}
}
}
return;
}
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(SCDSessionRef session, CFStringRef key)
{
CFDictionaryRef ent_dict = NULL;
SCDHandleRef ent_handle = NULL;
CFDictionaryRef if_dict = NULL;
SCDHandleRef if_handle = NULL;
CFStringRef if_key = NULL;
CFStringRef if_port;
CFMutableDictionaryRef new_dict = NULL;
static CFStringRef pre = NULL;
CFStringRef serviceID = NULL;
CFStringRef serviceType;
SCDStatus status;
if (pre == NULL) {
pre = SCDKeyCreate(CFSTR("%@/%@/%@/"),
kSCCacheDomainSetup,
kSCCompNetwork,
kSCCompService);
}
status = SCDGet(session, key, &ent_handle);
if (status != SCD_OK) {
goto done;
}
ent_dict = isA_CFDictionary(SCDHandleGetData(ent_handle));
if (ent_dict == NULL) {
goto done;
}
serviceID = parse_component(key, pre);
if (serviceID == NULL) {
goto done;
}
if_key = SCDKeyCreateNetworkServiceEntity(kSCCacheDomainSetup,
serviceID,
kSCEntNetInterface);
CFRelease(serviceID);
status = SCDGet(session, if_key, &if_handle);
CFRelease(if_key);
if (status != SCD_OK) {
goto done;
}
if_dict = isA_CFDictionary(SCDHandleGetData(if_handle));
if (if_dict == NULL) {
goto done;
}
if (!CFDictionaryGetValueIfPresent(if_dict,
kSCPropNetInterfaceType,
(void **)&serviceType) ||
!CFEqual(serviceType, kSCValNetInterfaceTypeEthernet)) {
goto done;
}
if_port = CFDictionaryGetValue(if_dict, kSCPropNetInterfaceDeviceName);
if (if_port == NULL) {
goto done;
}
new_dict = CFDictionaryCreateMutableCopy(NULL, 0, ent_dict);
CFDictionarySetValue(new_dict, kSCPropNetInterfaceDeviceName, if_port);
done:
if (ent_handle) SCDHandleRelease(ent_handle);
if (if_handle) SCDHandleRelease(if_handle);
return (CFDictionaryRef)new_dict;
}
static CFArrayRef
entity_all(SCDSessionRef session, CFStringRef entity, CFArrayRef order)
{
CFMutableArrayRef defined = NULL;
int i;
CFStringRef key;
CFMutableArrayRef ordered = NULL;
SCDStatus status;
ordered = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
key = SCDKeyCreateNetworkServiceEntity(kSCCacheDomainSetup, kSCCompAnyRegex, entity);
status = SCDList(session, key, kSCDRegexKey, &defined);
CFRelease(key);
if (status != SCD_OK) {
goto done;
}
if (CFArrayGetCount(defined) > 0) {
CFMutableArrayRef 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;
key = SCDKeyCreateNetworkServiceEntity(kSCCacheDomainSetup,
CFArrayGetValueAtIndex(order, i),
entity);
dict = entity_one(session, 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(session, 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 (name == NULL) {
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;
}
boolean_t
updateConfiguration()
{
boolean_t changed = FALSE;
CFStringRef computerName;
CFStringEncoding computerNameEncoding;
CFArrayRef config;
CFArrayRef configuredInterfaces = NULL;
SCDHandleRef handle;
CFIndex i;
CFIndex ifCount = 0;
CFStringRef key;
CFMutableArrayRef newConfig;
CFMutableArrayRef newConfigFile;
CFMutableDictionaryRef newDefaults;
CFMutableDictionaryRef newGlobals;
CFMutableDictionaryRef newZones;
CFNumberRef num;
CFStringRef primaryPort = NULL;
CFStringRef primaryZone = NULL;
SCDStatus scd_status;
CFArrayRef serviceOrder = NULL;
CFDictionaryRef setGlobals = NULL;
CFStringRef str;
boolean_t useFlatFiles = TRUE;
if (useFlatFiles) {
key = SCDKeyCreate(CFSTR("%@" "UseFlatFiles"), kSCCacheDomainSetup);
scd_status = SCDGet(session, key, &handle);
CFRelease(key);
switch (scd_status) {
case SCD_OK :
SCDHandleRelease(handle);
return FALSE;
case SCD_NOKEY :
useFlatFiles = FALSE;
break;
default :
SCDLog(LOG_ERR, CFSTR("SCDGet() failed: %s"), SCDError(scd_status));
return FALSE;
}
}
newConfigFile = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
newGlobals = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
newDefaults = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
newZones = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(newGlobals, CFSTR("APPLETALK"), CFSTR("-NO-"));
(void)SCDLock(session);
key = SCDKeyCreateNetworkGlobalEntity(kSCCacheDomainSetup, kSCEntNetAppleTalk);
scd_status = SCDGet(session, key, &handle);
CFRelease(key);
switch (scd_status) {
case SCD_OK :
setGlobals = SCDHandleGetData(handle);
CFRetain(setGlobals);
if ((CFDictionaryGetValueIfPresent(setGlobals,
kSCPropNetServiceOrder,
(void **)&serviceOrder) == TRUE)) {
CFRetain(serviceOrder);
}
SCDHandleRelease(handle);
break;
case SCD_NOKEY :
break;
default :
SCDLog(LOG_ERR, CFSTR("SCDGet() failed: %s"), SCDError(scd_status));
goto globalDone;
}
if (!serviceOrder) {
key = SCDKeyCreateNetworkGlobalEntity(kSCCacheDomainSetup, kSCEntNetIPv4);
scd_status = SCDGet(session, key, &handle);
CFRelease(key);
switch (scd_status) {
CFDictionaryRef ipv4Globals;
case SCD_OK :
ipv4Globals = SCDHandleGetData(handle);
if ((CFDictionaryGetValueIfPresent(ipv4Globals,
kSCPropNetServiceOrder,
(void **)&serviceOrder) == TRUE)) {
CFRetain(serviceOrder);
}
SCDHandleRelease(handle);
break;
case SCD_NOKEY :
break;
default :
SCDLog(LOG_ERR, CFSTR("SCDGet() failed: %s"), SCDError(scd_status));
goto globalDone;
}
}
configuredInterfaces = entity_all(session, kSCEntNetAppleTalk, serviceOrder);
if (configuredInterfaces) {
ifCount = CFArrayGetCount(configuredInterfaces);
}
globalDone :
(void)SCDUnlock(session);
if (serviceOrder) CFRelease(serviceOrder);
for (i=0; i<ifCount; i++) {
CFDictionaryRef service;
CFStringRef ifName;
SCDHandleRef handle = NULL;
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 = SCDKeyCreateNetworkInterfaceEntity(kSCCacheDomainState, ifName, kSCEntNetLink);
scd_status = SCDGet(session, key, &handle);
CFRelease(key);
switch (scd_status) {
CFDictionaryRef linkDict;
CFBooleanRef linkStatus;
case SCD_OK :
linkDict = SCDHandleGetData(handle);
linkStatus = CFDictionaryGetValue(linkDict, kSCPropNetLinkActive);
if ((linkStatus == NULL) || (linkStatus != kCFBooleanTrue)) {
goto nextIF;
}
break;
case SCD_NOKEY :
break;
default :
SCDLog(LOG_ERR, CFSTR("SCDGet() failed: %s"), SCDError(scd_status));
goto nextIF;
}
if (!CFDictionaryGetValueIfPresent(service,
kSCPropNetAppleTalkConfigMethod,
(void **)&configMethod)) {
goto nextIF;
}
if (!CFEqual(configMethod, kSCValNetAppleTalkConfigMethodNode ) &&
!CFEqual(configMethod, kSCValNetAppleTalkConfigMethodRouter ) &&
!CFEqual(configMethod, kSCValNetAppleTalkConfigMethodSeedRouter)) {
SCDLog(LOG_NOTICE,
CFSTR("Unexpected AppleTalk ConfigMethod: %@"),
configMethod);
goto nextIF;
}
portConfig = CFStringCreateMutable(NULL, 0);
CFStringAppendFormat(portConfig, NULL, CFSTR("%@:"), ifName);
if (CFEqual(configMethod, kSCValNetAppleTalkConfigMethodSeedRouter)) {
networkRange = CFDictionaryGetValue(service,
kSCPropNetAppleTalkSeedNetworkRange);
if ((networkRange == NULL) || (CFArrayGetCount(networkRange) == 0)) {
SCDLog(LOG_NOTICE,
CFSTR("AppleTalk configuration error (%@)"),
kSCPropNetAppleTalkSeedNetworkRange);
goto nextIF;
}
zoneList = CFDictionaryGetValue(service,
kSCPropNetAppleTalkSeedZones);
if ((zoneList == NULL) || ((zCount = CFArrayGetCount(zoneList)) == 0)) {
SCDLog(LOG_NOTICE,
CFSTR("AppleTalk configuration error (%@)"),
kSCPropNetAppleTalkSeedZones);
goto nextIF;
}
CFNumberGetValue(CFArrayGetValueAtIndex(networkRange, 0), kCFNumberIntType, &sNetwork);
if (CFArrayGetCount(networkRange) > 1) {
CFNumberGetValue(CFArrayGetValueAtIndex(networkRange, 1), kCFNumberIntType, &eNetwork);
} else {
eNetwork = sNetwork;
}
CFStringAppendFormat(portConfig, NULL, CFSTR("%d:%d:"), sNetwork, eNetwork);
for (j=0; j<zCount; j++) {
CFStringRef zone;
CFArrayRef ifList;
CFMutableArrayRef newIFList;
zone = CFArrayGetValueAtIndex(zoneList, j);
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 == NULL) {
primaryZone = CFRetain(zone);
}
}
}
computerName = CFDictionaryGetValue(service,
kSCPropNetAppleTalkComputerName);
if (CFDictionaryGetValueIfPresent(service,
kSCPropNetAppleTalkComputerNameEncoding,
(void **)&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);
if (CFDictionaryGetValueIfPresent(service,
kSCPropNetAppleTalkNetworkID,
(void **)&defaultNetwork) &&
CFDictionaryGetValueIfPresent(service,
kSCPropNetAppleTalkNodeID,
(void **)&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-"));
}
nextIF :
if (portConfig) CFRelease(portConfig);
if (handle) SCDHandleRelease(handle);
}
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)) {
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")) &&
(SCDHostNameGet(&computerName, &computerNameEncoding) == SCD_OK) &&
(computerName != NULL)) {
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) {
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 (setGlobals) CFRelease(setGlobals);
return changed;
}
boolean_t
atConfigChangedCallback(SCDSessionRef session, void *arg)
{
boolean_t configChanged;
SCDStatus scd_status;
CFArrayRef changedKeys;
scd_status = SCDNotifierGetChanges(session, &changedKeys);
if (scd_status == SCD_OK) {
CFRelease(changedKeys);
} else {
SCDLog(LOG_ERR, CFSTR("SCDNotifierGetChanges() failed: %s"), SCDError(scd_status));
}
configChanged = updateConfiguration();
if (configChanged) {
CFStringRef key;
key = SCDKeyCreate(CFSTR("%@%s"), kSCCacheDomainFile, AT_CFG_FILE);
scd_status = SCDTouch(session, key);
CFRelease(key);
if (scd_status != SCD_OK) {
SCDLog(LOG_ERR, CFSTR("SCDTouch() failed: %s"), SCDError(scd_status));
}
}
return TRUE;
}
void
prime()
{
SCDLog(LOG_DEBUG, CFSTR("prime() called"));
(void) updateConfiguration();
return;
}
void
start(const char *bundleName, const char *bundleDir)
{
SCDStatus scd_status;
CFStringRef key;
SCDLog(LOG_DEBUG, CFSTR("start() called"));
SCDLog(LOG_DEBUG, CFSTR(" bundle name = %s"), bundleName);
SCDLog(LOG_DEBUG, CFSTR(" bundle directory = %s"), bundleDir);
oldGlobals = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
oldConfigFile = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
oldDefaults = CFDictionaryCreateMutable(NULL,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
scd_status = SCDOpen(&session, CFSTR("AppleTalk Configuraton plug-in"));
if (scd_status != SCD_OK) {
SCDLog(LOG_ERR, CFSTR("SCDOpen() failed: %s"), SCDError(scd_status));
goto error;
}
key = SCDKeyCreateNetworkGlobalEntity(kSCCacheDomainSetup,
kSCEntNetAppleTalk);
scd_status = SCDNotifierAdd(session, key, kSCDRegexKey);
CFRelease(key);
if (scd_status != SCD_OK) {
SCDLog(LOG_NOTICE, CFSTR(" SCDNotifierAdd(): %s"), SCDError(scd_status));
goto error;
}
key = SCDKeyCreateNetworkServiceEntity(kSCCacheDomainSetup,
kSCCompAnyRegex,
kSCEntNetAppleTalk);
scd_status = SCDNotifierAdd(session, key, kSCDRegexKey);
CFRelease(key);
if (scd_status != SCD_OK) {
SCDLog(LOG_NOTICE, CFSTR(" SCDNotifierAdd(): %s"), SCDError(scd_status));
goto error;
}
key = SCDKeyCreateNetworkInterfaceEntity(kSCCacheDomainState,
kSCCompAnyRegex,
kSCEntNetLink);
scd_status = SCDNotifierAdd(session, key, kSCDRegexKey);
CFRelease(key);
if (scd_status != SCD_OK) {
SCDLog(LOG_NOTICE, CFSTR(" SCDNotifierAdd(): %s"), SCDError(scd_status));
goto error;
}
key = SCDKeyCreateHostName();
scd_status = SCDNotifierAdd(session, key, 0);
CFRelease(key);
if (scd_status != SCD_OK) {
SCDLog(LOG_NOTICE, CFSTR(" SCDNotifierAdd(): %s"), SCDError(scd_status));
goto error;
}
scd_status = SCDNotifierInformViaCallback(session, atConfigChangedCallback, NULL);
if (scd_status != SCD_OK) {
SCDLog(LOG_NOTICE, CFSTR("SCDNotifierInformViaCallback() failed: %s"), SCDError(scd_status));
goto error;
}
return;
error :
if (session) (void) SCDClose(&session);
return;
}