-/*
- * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-/*
- * Modification History
- *
- * March 15, 2003 Allan Nathanson <ajn@apple.com>
- * - startup/shutdown AT networking without Kicker's help and
- * publish the state information after the configuration is
- * active.
- *
- * April 29, 2002 Allan Nathanson <ajn@apple.com>
- * - add global state information (primary service, interface)
- *
- * June 24, 2001 Allan Nathanson <ajn@apple.com>
- * - update to public SystemConfiguration.framework APIs
- *
- * July 7, 2000 Allan Nathanson <ajn@apple.com>
- * - initial revision
- */
-
-
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/param.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/utsname.h>
-#include <sys/wait.h>
-#include <dlfcn.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 <CoreFoundation/CoreFoundation.h>
-#include <SystemConfiguration/SystemConfiguration.h>
-#include <SystemConfiguration/SCPrivate.h>
-#include <SystemConfiguration/SCDPlugin.h>
-#include <SystemConfiguration/SCValidation.h>
-
-#include "cache.h"
-#include "cfManager.h"
-
-#define HOSTCONFIG "/etc/hostconfig"
-
-static SCDynamicStoreRef store = NULL;
-static CFRunLoopSourceRef storeRls = NULL;
-
-static int curState = 0; // abs(state) == sequence #, < 0 == stop, > 0 == start
-static CFMutableDictionaryRef curGlobals = NULL;
-static CFMutableArrayRef curConfigFile = NULL;
-static CFMutableDictionaryRef curDefaults = NULL;
-static CFMutableDictionaryRef curStartup = NULL;
-
-static Boolean _verbose = FALSE;
-
-
-#define RETRY_DELAY 2.0 // seconds
-#define RETRY_LIMIT 5 // # of startup/shutdown attempts
-
-static void startAppleTalk(CFRunLoopTimerRef timer, void *info);
-static void stopAppleTalk (CFRunLoopTimerRef timer, void *info);
-
-
-static void *
-__loadAppleTalk(void) {
- static void *image = NULL;
- if (NULL == image) {
- const char *framework = "/System/Library/Frameworks/AppleTalk.framework/Versions/A/AppleTalk";
- struct stat statbuf;
- const char *suffix = getenv("DYLD_IMAGE_SUFFIX");
- char path[MAXPATHLEN];
-
- strlcpy(path, framework, sizeof(path));
- if (suffix) strlcat(path, suffix, sizeof(path));
- if (0 <= stat(path, &statbuf)) {
- image = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
- } else {
- image = dlopen(framework, RTLD_LAZY | RTLD_LOCAL);
- }
- }
- return (void *)image;
-}
-
-
-static int
-_at_setdefaultaddr(char *ifName, struct at_addr *init_address)
-{
- #undef at_setdefaultaddr
- static typeof (at_setdefaultaddr) *dyfunc = NULL;
- if (!dyfunc) {
- void *image = __loadAppleTalk();
- if (image) dyfunc = dlsym(image, "at_setdefaultaddr");
- }
- return dyfunc ? dyfunc(ifName, init_address) : -1;
-}
-#define at_setdefaultaddr _at_setdefaultaddr
-
-
-static int
-_at_setdefaultzone(char *ifName, at_nvestr_t *zone)
-{
- #undef at_setdefaultzone
- static typeof (at_setdefaultzone) *dyfunc = NULL;
- if (!dyfunc) {
- void *image = __loadAppleTalk();
- if (image) dyfunc = dlsym(image, "at_setdefaultzone");
- }
- return dyfunc ? dyfunc(ifName, zone) : -1;
-}
-#define at_setdefaultzone _at_setdefaultzone
-
-
-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(curDefaults, ifName, (const void **)&oldDict) ||
- !CFEqual(oldDict, newDict)) {
- char ifr_name[IFNAMSIZ + 1];
-
- bzero(&ifr_name, sizeof(ifr_name));
- if (!_SC_cfstring_to_cstring(ifName, ifr_name, sizeof(ifr_name), kCFStringEncodingASCII)) {
- SCLog(TRUE, LOG_ERR, CFSTR("could not convert interface name to C string"));
- return;
- }
-
- /*
- * Set preferred Network and Node ID
- */
- if (CFDictionaryGetValueIfPresent(newDict,
- kSCPropNetAppleTalkNetworkID,
- (const void **)&defaultNetwork) &&
- CFDictionaryGetValueIfPresent(newDict,
- kSCPropNetAppleTalkNodeID,
- (const void **)&defaultNode)
- ) {
- struct at_addr init_address;
- int status;
-
- /*
- * set the default node and network
- */
- 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"));
- return;
- }
- }
-
- /*
- * Set default zone
- */
- if (CFDictionaryGetValueIfPresent(newDict,
- kSCPropNetAppleTalkDefaultZone,
- (const void **)&defaultZone)
- ) {
- int status;
- at_nvestr_t zone;
-
- /*
- * set the "default zone" for this interface
- */
- bzero(&zone, sizeof(zone));
- if (!_SC_cfstring_to_cstring(defaultZone,
- (char *)zone.str,
- sizeof(zone.str),
- kCFStringEncodingASCII)) {
- SCLog(TRUE, LOG_ERR, CFSTR("could not convert default zone to C string"));
- return;
- }
-
- zone.len = strlen((const char *)zone.str);
- status = at_setdefaultzone(ifr_name, &zone);
- if (status == -1) {
- SCLog(TRUE, LOG_ERR, CFSTR("at_setdefaultzone() failed"));
- return;
- }
- }
- }
-
- 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;
-}
-
-
-/*
- * Function: parse_component
- * Purpose:
- * Given a string 'key' and a string prefix 'prefix',
- * return the next component in the slash '/' separated
- * key.
- *
- * Examples:
- * 1. key = "a/b/c" prefix = "a/"
- * returns "b"
- * 2. key = "a/b/c" prefix = "a/b/"
- * returns "c"
- */
-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);
- }
-
- /*
- * get entity dictionary for service
- */
- ent_dict = cache_SCDynamicStoreCopyValue(store, key);
- if (!isA_CFDictionary(ent_dict)) {
- goto done;
- }
-
- /*
- * get interface dictionary for service
- */
- serviceID = parse_component(key, pre);
- if (!serviceID) {
- goto done;
- }
-
- if_key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
- kSCDynamicStoreDomainSetup,
- serviceID,
- kSCEntNetInterface);
- if_dict = cache_SCDynamicStoreCopyValue(store, if_key);
- CFRelease(if_key);
- if (!isA_CFDictionary(if_dict)) {
- goto done;
- }
-
- /* check the interface type */
- serviceType = CFDictionaryGetValue(if_dict,
- kSCPropNetInterfaceType);
- if (!isA_CFString(serviceType) ||
- !CFEqual(serviceType, kSCValNetInterfaceTypeEthernet)) {
- /* sorry, no AT networking on this interface */
- goto done;
- }
-
- /*
- * get port name (from interface dictionary).
- */
- if_port = CFDictionaryGetValue(if_dict, kSCPropNetInterfaceDeviceName);
- if (!isA_CFString(if_port)) {
- goto done;
- }
-
- /*
- * add ServiceID and interface port name to entity dictionary.
- */
- 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;
- CFIndex i;
- CFIndex n;
- 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;
- }
-
- n = order ? CFArrayGetCount(order) : 0;
- for (i = 0; i < n; 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 != kCFNotFound) {
- CFArrayRemoveValueAtIndex(defined, j);
- }
-
- CFRelease(key);
- }
-
- n = CFArrayGetCount(defined);
- for (i = 0; i < n; 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 void
-encodeName(CFStringRef name,
- CFStringEncoding encoding,
- CFMutableDictionaryRef startup,
- CFMutableDictionaryRef globals)
-{
- CFDataRef bytes;
- CFMutableStringRef encodedName = NULL;
- CFIndex len;
-
- if (!isA_CFString(name)) {
- return;
- }
-
- if (encoding == kCFStringEncodingASCII) {
- encodedName = (CFMutableStringRef)CFStringCreateCopy(NULL, name);
- goto done;
- }
-
- /*
- * encode the potentially non-printable string
- */
- bytes = CFStringCreateExternalRepresentation(NULL,
- name,
- encoding,
- 0);
- if (bytes) {
- unsigned char *byte;
- CFIndex i;
-
- /*
- * check if the MacRoman string can be represented as ASCII
- */
- if (encoding == kCFStringEncodingMacRoman) {
- CFDataRef ascii;
-
- ascii = CFStringCreateExternalRepresentation(NULL,
- name,
- kCFStringEncodingASCII,
- 0);
- if (ascii) {
- CFRelease(ascii);
- CFRelease(bytes);
- encodedName = (CFMutableStringRef)CFStringCreateCopy(NULL, name);
- goto done;
- }
- }
-
- 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);
- }
-
- /*
- * add "encoded string" markers
- */
- CFStringInsert(encodedName, 0, CFSTR("*"));
- CFStringAppend(encodedName, CFSTR("*"));
-
- CFRelease(bytes);
- }
-
- done :
-
- if (encodedName) {
- if (startup) {
- /* update "startup" dictionary */
- CFDictionaryAddValue(startup, CFSTR("APPLETALK_HOSTNAME"), encodedName);
- }
-
- if (globals) {
- CFNumberRef num;
-
- /* update "global" dictionary */
- num = CFNumberCreate(NULL, kCFNumberIntType, &encoding);
- CFDictionaryAddValue(globals, kSCPropNetAppleTalkComputerName, name);
- CFDictionaryAddValue(globals, kSCPropNetAppleTalkComputerNameEncoding, num);
- CFRelease(num);
- }
-
- CFRelease(encodedName);
- }
-
- return;
-}
-
-
-static boolean_t
-updateConfiguration(int *newState)
-{
- boolean_t changed = FALSE;
- CFStringRef computerName;
- CFStringEncoding computerNameEncoding;
- CFArrayRef configuredServices = NULL;
- CFDictionaryRef dict;
- CFIndex i;
- CFIndex ifCount = 0;
- CFMutableArrayRef info = NULL;
- CFArrayRef interfaces = NULL;
- CFStringRef key;
- CFArrayRef keys;
- CFIndex n;
- CFMutableArrayRef newConfigFile;
- CFMutableDictionaryRef newDefaults;
- CFMutableDictionaryRef newDict;
- CFMutableDictionaryRef newGlobals;
- CFMutableDictionaryRef newGlobalsX; /* newGlobals without ServiceID */
- CFMutableDictionaryRef newStartup;
- CFMutableDictionaryRef newZones;
- CFNumberRef num;
- CFMutableDictionaryRef curGlobalsX; /* curGlobals without ServiceID */
- CFStringRef pattern;
- boolean_t postGlobals = FALSE;
- CFStringRef primaryPort = NULL; /* primary interface */
- CFStringRef primaryZone = NULL;
- CFArrayRef serviceOrder = NULL;
- CFDictionaryRef setGlobals = NULL;
-
- cache_open();
-
- /*
- * establish the "new" AppleTalk configuration
- */
- *newState = curState;
- newConfigFile = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
- newGlobals = CFDictionaryCreateMutable(NULL,
- 0,
- &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks);
- newDefaults = CFDictionaryCreateMutable(NULL,
- 0,
- &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks);
- newStartup = CFDictionaryCreateMutable(NULL,
- 0,
- &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks);
- newZones = CFDictionaryCreateMutable(NULL,
- 0,
- &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks);
-
- /* initialize overall state */
- CFDictionarySetValue(newStartup, CFSTR("APPLETALK"), CFSTR("-NO-"));
-
- /*
- * get the global settings (ServiceOrder, ComputerName, ...)
- */
- key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
- kSCDynamicStoreDomainSetup,
- kSCEntNetAppleTalk);
- setGlobals = cache_SCDynamicStoreCopyValue(store, key);
- CFRelease(key);
- if (setGlobals) {
- if (isA_CFDictionary(setGlobals)) {
- /* get service order */
- serviceOrder = CFDictionaryGetValue(setGlobals,
- kSCPropNetServiceOrder);
- serviceOrder = isA_CFArray(serviceOrder);
- if (serviceOrder) {
- CFRetain(serviceOrder);
- }
- } else {
- CFRelease(setGlobals);
- setGlobals = NULL;
- }
- }
-
- /*
- * if we don't have an AppleTalk ServiceOrder, use IPv4's (if defined)
- */
- if (!serviceOrder) {
- key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
- kSCDynamicStoreDomainSetup,
- kSCEntNetIPv4);
- dict = cache_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);
- }
- }
-
- /*
- * get the list of ALL configured services
- */
- configuredServices = entity_all(store, kSCEntNetAppleTalk, serviceOrder);
- if (configuredServices) {
- ifCount = CFArrayGetCount(configuredServices);
- }
-
- if (serviceOrder) CFRelease(serviceOrder);
-
- /*
- * get the list of ALL active interfaces
- */
- key = SCDynamicStoreKeyCreateNetworkInterface(NULL, kSCDynamicStoreDomainState);
- dict = cache_SCDynamicStoreCopyValue(store, key);
- CFRelease(key);
- if (dict) {
- if (isA_CFDictionary(dict)) {
- interfaces = CFDictionaryGetValue(dict,
- kSCDynamicStorePropNetInterfaces);
- interfaces = isA_CFArray(interfaces);
- if (interfaces) {
- CFRetain(interfaces);
- }
- }
- CFRelease(dict);
- }
-
- /*
- * get the list of previously configured services
- */
- pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
- kSCDynamicStoreDomainState,
- kSCCompAnyRegex,
- kSCEntNetAppleTalk);
- keys = SCDynamicStoreCopyKeyList(store, pattern);
- CFRelease(pattern);
- if (keys) {
- info = CFArrayCreateMutableCopy(NULL, 0, keys);
- CFRelease(keys);
- }
-
- /*
- * iterate over each configured service to establish the new
- * configuration.
- */
- for (i = 0; i < ifCount; i++) {
- CFDictionaryRef service;
- CFStringRef ifName;
- CFStringRef configMethod;
- CFMutableStringRef portConfig = NULL;
- CFArrayRef networkRange; /* for seed ports, CFArray[2] of CFNumber (lo, hi) */
- int sNetwork;
- int eNetwork;
- CFArrayRef zoneList; /* for seed ports, CFArray[] of CFString (zones names) */
- CFIndex zCount;
- CFIndex j;
- CFMutableDictionaryRef ifDefaults = NULL;
- CFNumberRef defaultNetwork;
- CFNumberRef defaultNode;
- CFStringRef defaultZone;
-
- /* get AppleTalk service dictionary */
- service = CFArrayGetValueAtIndex(configuredServices, i);
-
- /* get interface name */
- ifName = CFDictionaryGetValue(service, kSCPropNetInterfaceDeviceName);
-
- /* check inteface availability */
- if (!interfaces ||
- !CFArrayContainsValue(interfaces, CFRangeMake(0, CFArrayGetCount(interfaces)), ifName)) {
- /* if interface not available */
- goto nextIF;
- }
-
- /* check interface link status */
- key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
- kSCDynamicStoreDomainState,
- ifName,
- kSCEntNetLink);
- dict = cache_SCDynamicStoreCopyValue(store, key);
- CFRelease(key);
- if (dict) {
- Boolean linkStatus = TRUE; /* assume the link is "up" */
- Boolean ifDetaching = FALSE; /* assume link is not detaching */
-
- /* the link key for this interface is available */
- if (isA_CFDictionary(dict)) {
- CFBooleanRef bVal;
-
- bVal = CFDictionaryGetValue(dict, kSCPropNetLinkActive);
- if (isA_CFBoolean(bVal)) {
- linkStatus = CFBooleanGetValue(bVal);
- }
-
- /* check if interface is detaching - value
- doesn't really matter, only that it exists */
- ifDetaching = CFDictionaryContainsKey(dict, kSCPropNetLinkDetaching);
- }
- CFRelease(dict);
-
- if (!linkStatus || ifDetaching) {
- /* if link status down or the interface is detaching */
- goto nextIF;
- }
- }
-
- /*
- * Determine configuration method for this service
- */
- configMethod = CFDictionaryGetValue(service, kSCPropNetAppleTalkConfigMethod);
- if (!isA_CFString(configMethod)) {
- /* if no ConfigMethod */
- goto nextIF;
- }
-
- if (!CFEqual(configMethod, kSCValNetAppleTalkConfigMethodNode ) &&
- !CFEqual(configMethod, kSCValNetAppleTalkConfigMethodRouter ) &&
- !CFEqual(configMethod, kSCValNetAppleTalkConfigMethodSeedRouter)) {
- /* if not one of the expected values, disable */
- SCLog(TRUE, LOG_NOTICE,
- CFSTR("Unexpected AppleTalk ConfigMethod: %@"),
- configMethod);
- goto nextIF;
- }
-
- /*
- * the first service to be defined will always be "primary"
- */
- if (CFArrayGetCount(newConfigFile) == 0) {
- CFDictionaryRef active;
-
- CFDictionarySetValue(newGlobals,
- kSCDynamicStorePropNetPrimaryService,
- CFDictionaryGetValue(service, CFSTR("ServiceID")));
- CFDictionarySetValue(newGlobals,
- kSCDynamicStorePropNetPrimaryInterface,
- ifName);
-
- /* and check if AT newtorking is active on the primary interface */
- key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
- kSCDynamicStoreDomainState,
- ifName,
- kSCEntNetAppleTalk);
- active = cache_SCDynamicStoreCopyValue(store, key);
- CFRelease(key);
- if (active) {
- if (isA_CFDictionary(active)) {
- postGlobals = TRUE;
- }
- CFRelease(active);
- }
- }
-
- /*
- * define the port
- */
- portConfig = CFStringCreateMutable(NULL, 0);
- CFStringAppendFormat(portConfig, NULL, CFSTR("%@:"), ifName);
-
- if (CFEqual(configMethod, kSCValNetAppleTalkConfigMethodSeedRouter)) {
- CFNumberRef num;
-
- /*
- * we have been asked to configure this interface as a
- * seed port. Ensure that we have been provided at least
- * one network number, have been provided with at least
- * one zonename, ...
- */
-
- networkRange = CFDictionaryGetValue(service,
- kSCPropNetAppleTalkSeedNetworkRange);
- if (!isA_CFArray(networkRange) || (CFArrayGetCount(networkRange) == 0)) {
- SCLog(TRUE, LOG_NOTICE,
- CFSTR("AppleTalk configuration error (%@)"),
- kSCPropNetAppleTalkSeedNetworkRange);
- goto nextIF;
- }
-
- /*
- * establish the starting and ending network numbers
- */
- 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);
-
- /*
- * establish the zones associated with this port
- */
- 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, (const void **)&ifList)) {
- /* known zone */
- newIFList = CFArrayCreateMutableCopy(NULL, 0, ifList);
- } else {
- /* new zone */
- newIFList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
- }
- CFArrayAppendValue(newIFList, ifName);
- CFArraySortValues(newIFList,
- CFRangeMake(0, CFArrayGetCount(newIFList)),
- (CFComparatorFunction)CFStringCompare,
- NULL);
- CFDictionarySetValue(newZones, zone, newIFList);
- CFRelease(newIFList);
-
- /*
- * flag the default zone
- */
- if (!primaryZone) {
- primaryZone = CFRetain(zone);
- }
- }
- if (!primaryZone) {
- SCLog(TRUE, LOG_NOTICE,
- CFSTR("AppleTalk configuration error (%@)"),
- kSCPropNetAppleTalkSeedZones);
- goto nextIF;
- }
- }
-
- /* get the (per-interface) "Computer Name" */
- computerName = CFDictionaryGetValue(service,
- kSCPropNetAppleTalkComputerName);
- if (CFDictionaryGetValueIfPresent(service,
- kSCPropNetAppleTalkComputerNameEncoding,
- (const void **)&num) &&
- isA_CFNumber(num)) {
- CFNumberGetValue(num, kCFNumberIntType, &computerNameEncoding);
- } else {
- computerNameEncoding = CFStringGetSystemEncoding();
- }
- encodeName(computerName, computerNameEncoding, newStartup, newGlobals);
-
- /*
- * declare the first configured AppleTalk service / interface
- * as the "home port".
- */
- if (CFArrayGetCount(newConfigFile) == 0) {
- CFStringAppend(portConfig, CFSTR("*"));
- primaryPort = CFRetain(ifName);
- }
- CFArrayAppendValue(newConfigFile, portConfig);
-
- /*
- * get the per-interface defaults
- */
- ifDefaults = CFDictionaryCreateMutable(NULL,
- 0,
- &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks);
-
- defaultNetwork = CFDictionaryGetValue(service, kSCPropNetAppleTalkNetworkID);
- defaultNode = CFDictionaryGetValue(service, kSCPropNetAppleTalkNodeID);
- if (isA_CFNumber(defaultNetwork) && isA_CFNumber(defaultNode)) {
- /*
- * set the default node and network
- */
- CFDictionarySetValue(ifDefaults,
- kSCPropNetAppleTalkNetworkID,
- defaultNetwork);
- CFDictionarySetValue(ifDefaults,
- kSCPropNetAppleTalkNodeID,
- defaultNode);
- }
-
- if ((CFDictionaryGetValueIfPresent(service,
- kSCPropNetAppleTalkDefaultZone,
- (const void **)&defaultZone) == TRUE)) {
- /*
- * set the default zone for this interface
- */
- CFDictionarySetValue(ifDefaults,
- kSCPropNetAppleTalkDefaultZone,
- defaultZone);
- }
-
- CFDictionarySetValue(newDefaults, ifName, ifDefaults);
- CFRelease(ifDefaults);
-
- switch (CFArrayGetCount(newConfigFile)) {
- case 1:
- /*
- * first AppleTalk interface
- */
- CFDictionarySetValue(newStartup, CFSTR("APPLETALK"), ifName);
- break;
- case 2:
- /* second AppleTalk interface */
- if (!CFEqual(CFDictionaryGetValue(newStartup, CFSTR("APPLETALK")),
- CFSTR("-ROUTER-"))) {
- /*
- * if not routing (yet), configure as multi-home
- */
- CFDictionarySetValue(newStartup, CFSTR("APPLETALK"), CFSTR("-MULTIHOME-"));
- }
- break;
- }
-
- if (CFEqual(configMethod, kSCValNetAppleTalkConfigMethodRouter) ||
- CFEqual(configMethod, kSCValNetAppleTalkConfigMethodSeedRouter)) {
- /* if not a simple node, enable routing */
- CFDictionarySetValue(newStartup, CFSTR("APPLETALK"), CFSTR("-ROUTER-"));
- }
-
- /*
- * establish the State:/Network/Service/nnn/AppleTalk key info
- */
- key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
- kSCDynamicStoreDomainState,
- CFDictionaryGetValue(service, CFSTR("ServiceID")),
- kSCEntNetAppleTalk);
- newDict = CFDictionaryCreateMutable(NULL,
- 0,
- &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks);
- CFDictionaryAddValue(newDict, kSCPropInterfaceName, ifName);
- cache_SCDynamicStoreSetValue(store, key, newDict);
- CFRelease(newDict);
- if (info) {
- j = CFArrayGetFirstIndexOfValue(info,
- CFRangeMake(0, CFArrayGetCount(info)),
- key);
- if (j != kCFNotFound) {
- CFArrayRemoveValueAtIndex(info, 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);
- }
-
- /* sort the ports */
- i = CFArrayGetCount(newConfigFile);
- CFArraySortValues(newConfigFile,
- CFRangeMake(0, i),
- (CFComparatorFunction)CFStringCompare,
- NULL);
-
- /* add the zones to the configuration */
- CFDictionaryApplyFunction(newZones, addZoneToPorts, newConfigFile);
- CFRelease(newZones);
-
- /* sort the zones */
- CFArraySortValues(newConfigFile,
- CFRangeMake(i, CFArrayGetCount(newConfigFile)-i),
- (CFComparatorFunction)CFStringCompare,
- NULL);
-
- /* ensure that the last line of the configuration file is terminated */
- CFArrayAppendValue(newConfigFile, CFSTR(""));
-
- /*
- * Check if we have a "ComputerName" and look elsewhere if we don't have
- * one yet.
- */
- if (!CFDictionaryContainsKey(newStartup, CFSTR("APPLETALK_HOSTNAME")) &&
- (setGlobals != NULL)) {
- computerName = CFDictionaryGetValue(setGlobals,
- kSCPropNetAppleTalkComputerName);
- if (CFDictionaryGetValueIfPresent(setGlobals,
- kSCPropNetAppleTalkComputerNameEncoding,
- (const void **)&num) &&
- isA_CFNumber(num)) {
- CFNumberGetValue(num, kCFNumberIntType, &computerNameEncoding);
- } else {
- computerNameEncoding = CFStringGetSystemEncoding();
- }
- encodeName(computerName, computerNameEncoding, newStartup, newGlobals);
- }
- if (!CFDictionaryContainsKey(newStartup, CFSTR("APPLETALK_HOSTNAME"))) {
- computerName = SCDynamicStoreCopyComputerName(store, &computerNameEncoding);
- if (computerName) {
- encodeName(computerName, computerNameEncoding, newStartup, newGlobals);
- CFRelease(computerName);
- }
- }
- if (!CFDictionaryContainsKey(newStartup, CFSTR("APPLETALK_HOSTNAME"))) {
- struct utsname name;
-
- if (uname(&name) == 0) {
- computerName = CFStringCreateWithCString(NULL, name.nodename, kCFStringEncodingASCII);
- if (computerName) {
- encodeName(computerName, kCFStringEncodingASCII, NULL, newGlobals);
- CFRelease(computerName);
- }
- }
- }
-
- /* compare the previous and current configurations */
-
- curGlobalsX = CFDictionaryCreateMutableCopy(NULL, 0, curGlobals);
- CFDictionaryRemoveValue(curGlobalsX, kSCDynamicStorePropNetPrimaryService);
-
- newGlobalsX = CFDictionaryCreateMutableCopy(NULL, 0, newGlobals);
- CFDictionaryRemoveValue(newGlobalsX, kSCDynamicStorePropNetPrimaryService);
-
- key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
- kSCDynamicStoreDomainState,
- kSCEntNetAppleTalk);
-
- if (CFEqual(curGlobalsX , newGlobalsX ) &&
- CFEqual(curConfigFile , newConfigFile) &&
- CFEqual(curDefaults , newDefaults ) &&
- CFEqual(curStartup , newStartup )
- ) {
- /*
- * the configuration has not changed.
- */
-
- if (postGlobals) {
- /*
- * the requested configuration hasn't changed but we
- * now need to tell everyone that AppleTalk is active.
- */
- if (!SCDynamicStoreSetValue(store, key, newGlobals)) {
- SCLog(TRUE,
- LOG_ERR,
- CFSTR("SCDynamicStoreSetValue() failed: %s"),
- SCErrorString(SCError()));
- }
- }
-
- CFRelease(newGlobals);
- CFRelease(newConfigFile);
- CFRelease(newDefaults);
- CFRelease(newStartup);
- } else if (CFArrayGetCount(newConfigFile) <= 1) {
- /*
- * the configuration has changed but there are no
- * longer any interfaces configured for AppleTalk
- * networking.
- */
-
- /*
- * remove the global (State:/Network/Global/AppleTalk) key.
- *
- * Note: it will be restored later after AT networking has
- * been activated.
- */
-
- /* remove the (/etc/appletalk.cfg) configuration file */
- (void)unlink(AT_CFG_FILE);
-
- /*
- * update the per-service (and global) state
- */
- cache_SCDynamicStoreRemoveValue(store, key); // remove State:/Network/Global/AppleTalk
- n = CFArrayGetCount(info);
- for (i = 0; i < n; i++) {
- CFStringRef xKey = CFArrayGetValueAtIndex(info, i);
-
- cache_SCDynamicStoreRemoveValue(store, xKey);
- }
- cache_write(store);
-
- /* flag this as a new configuration */
- *newState = -(abs(curState) + 1);
- changed = TRUE;
- } else {
- /*
- * the configuration has changed.
- */
-
- /* update the (/etc/appletalk.cfg) configuration file */
- configWrite(AT_CFG_FILE, newConfigFile);
-
- /*
- * update the per-service (and global) state
- *
- * Note: if present, we remove any existing global state key and allow it
- * to be restored after the stack has been re-started.
- */
- CFDictionaryApplyFunction(newDefaults, updateDefaults, NULL);
- cache_SCDynamicStoreRemoveValue(store, key); // remove State:/Network/Global/AppleTalk
- n = CFArrayGetCount(info);
- for (i = 0; i < n; i++) {
- CFStringRef xKey = CFArrayGetValueAtIndex(info, i);
-
- cache_SCDynamicStoreRemoveValue(store, xKey);
- }
- cache_write(store);
-
- /* flag this as a new configuration */
- *newState = abs(curState) + 1;
- changed = TRUE;
- }
-
- CFRelease(curGlobalsX);
- CFRelease(newGlobalsX);
- CFRelease(key);
-
- if (changed) {
- CFRelease(curGlobals);
- curGlobals = newGlobals;
- CFRelease(curConfigFile);
- curConfigFile = newConfigFile;
- CFRelease(curDefaults);
- curDefaults = newDefaults;
- CFRelease(curStartup);
- curStartup = newStartup;
- }
-
- if (info) CFRelease(info);
- if (interfaces) CFRelease(interfaces);
- if (configuredServices) CFRelease(configuredServices);
- if (setGlobals) CFRelease(setGlobals);
-
- cache_close();
-
- return changed;
-}
-
-
-#include <sysexits.h>
-#define AT_CMD_SUCCESS EX_OK /* success */
-#define AT_CMD_ALREADY_RUNNING EX__MAX + 10
-#define AT_CMD_NOT_RUNNING EX__MAX + 11
-
-
-static int
-stackState()
-{
- int ret;
- int sock;
- at_state_t state;
-
- sock = socket(AF_APPLETALK, SOCK_RAW, 0);
- ret = ioctl(sock, AIOCGETSTATE, (caddr_t)&state);
- (void)close(sock);
- if (ret == -1) {
- SCLog(TRUE, LOG_DEBUG, CFSTR("ioctl(AIOCGETSTATE) failed: %s"), strerror(errno));
- return FALSE;
- }
-
- if (state.flags & AT_ST_STARTED) {
- return abs(curState);
- } else {
- return -(abs(curState));
- }
-}
-
-
-static pid_t execCommand = 0;
-static int execRetry;
-
-
-static void
-stopComplete(pid_t pid, int status, struct rusage *rusage, void *context)
-{
- execCommand = 0;
-
- if (WIFEXITED(status)) {
- switch (WEXITSTATUS(status)) {
- case AT_CMD_SUCCESS :
- case AT_CMD_NOT_RUNNING :
- SCLog(TRUE, LOG_NOTICE, CFSTR("AppleTalk shutdown complete"));
- if (curState > 0) {
- // the stack is down but we really want it up
- startAppleTalk(NULL, (void *)curState);
- }
- return;
- default :
- break;
- }
- }
-
- SCLog(TRUE,
- (execRetry > 1) ? LOG_NOTICE : LOG_ERR,
- CFSTR("AppleTalk shutdown failed, status = %d%s"),
- WEXITSTATUS(status),
- (execRetry > 1) ? " (retrying)" : "");
-
- // shutdown failed, retry
- if (--execRetry > 0) {
- CFRunLoopTimerContext timerContext = { 0, (void *)curState, NULL, NULL, NULL };
- CFRunLoopTimerRef timer;
-
- timer = CFRunLoopTimerCreate(NULL,
- CFAbsoluteTimeGetCurrent() + RETRY_DELAY,
- 0.0,
- 0,
- 0,
- stopAppleTalk,
- &timerContext);
- CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode);
- CFRelease(timer);
- return;
- } else {
- // we weren't able to stop
- curState = stackState();
- }
-
- return;
-}
-
-
-static void
-stopAppleTalk(CFRunLoopTimerRef timer, void *info)
-{
- char *argv[] = { "appletalk",
- "-d",
- NULL };
-
- if (execCommand == 0) {
- SCLog(TRUE, LOG_NOTICE, CFSTR("AppleTalk shutdown"));
- } else {
- SCLog(TRUE, LOG_NOTICE, CFSTR("AppleTalk shutdown skipped, transition in progress"));
- return;
- }
-
- execCommand = _SCDPluginExecCommand(stopComplete, // callback
- info, // context
- 0, // uid
- 0, // gid
- "/usr/sbin/appletalk", // path
- argv); // argv
-
- if (!timer) {
- execRetry = RETRY_LIMIT; // initialize retry count
- }
-
- return;
-}
-
-
-static void
-startComplete(pid_t pid, int status, struct rusage *rusage, void *context)
-{
- execCommand = 0;
-
- if (WIFEXITED(status)) {
- switch (WEXITSTATUS(status)) {
- case AT_CMD_SUCCESS :
- SCLog(TRUE, LOG_NOTICE, CFSTR("AppleTalk startup complete"));
- if ((curState < 0) || (curState > (int)context)) {
- // the stack is now up but we really want it down
- stopAppleTalk(NULL, (void *)curState);
- }
- return;
- case AT_CMD_ALREADY_RUNNING :
- // the stack is already up but we're not sure
- // if the configuration is correct, restart
- SCLog(TRUE, LOG_NOTICE, CFSTR("AppleTalk already running, restarting"));
- stopAppleTalk(NULL, (void *)curState);
- return;
- default :
- break;
- }
- }
-
- SCLog(TRUE,
- (execRetry > 1) ? LOG_NOTICE : LOG_ERR,
- CFSTR("AppleTalk startup failed, status = %d%s"),
- WEXITSTATUS(status),
- (execRetry > 1) ? " (retrying)" : "");
-
- // startup failed, retry
- if (--execRetry > 0) {
- CFRunLoopTimerContext timerContext = { 0, (void *)curState, NULL, NULL, NULL };
- CFRunLoopTimerRef timer;
-
- timer = CFRunLoopTimerCreate(NULL,
- CFAbsoluteTimeGetCurrent() + RETRY_DELAY,
- 0.0,
- 0,
- 0,
- startAppleTalk,
- &timerContext);
- CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode);
- CFRelease(timer);
- return;
- } else {
- // we weren't able to start
- curState = stackState();
- }
-
- return;
-}
-
-
-static void
-startAppleTalk(CFRunLoopTimerRef timer, void *info)
-{
- int argc = 0;
- char *argv[8];
- char *computerName = NULL;
- char *interface = NULL;
- CFStringRef mode = CFDictionaryGetValue(curStartup, CFSTR("APPLETALK"));
- CFStringRef name = CFDictionaryGetValue(curStartup, CFSTR("APPLETALK_HOSTNAME"));
-
- if (execCommand == 0) {
- SCLog(TRUE, LOG_NOTICE, CFSTR("AppleTalk startup"));
- } else {
- SCLog(TRUE, LOG_NOTICE, CFSTR("AppleTalk startup skipped, transition in progress"));
- return;
- }
-
- if (!mode) {
- // Huh?
- return;
- }
-
- // set command name
- argv[argc++] = "appletalk";
-
- // set hostname
- if (name) {
- computerName = _SC_cfstring_to_cstring(name, NULL, 0, kCFStringEncodingASCII);
- if (computerName) {
- argv[argc++] = "-C";
- argv[argc++] = computerName;
- } else {
- // could not convert name
- goto done;
- }
- }
-
- // set mode
- if (CFEqual(mode, CFSTR("-ROUTER-"))) {
- argv[argc++] = "-r";
- } else if (CFEqual(mode, CFSTR("-MULTIHOME-"))) {
- argv[argc++] = "-x";
- } else {
- interface = _SC_cfstring_to_cstring(mode, NULL, 0, kCFStringEncodingASCII);
- if (interface) {
- argv[argc++] = "-u";
- argv[argc++] = interface;
- } else {
- // could not convert interface
- goto done;
- }
- }
-
- // set non-interactive
- argv[argc++] = "-q";
-
- // close argument list
- argv[argc++] = NULL;
-
- execCommand = _SCDPluginExecCommand(startComplete, // callback
- info, // context
- 0, // uid
- 0, // gid
- "/usr/sbin/appletalk", // path
- argv); // argv
-
- if (!timer) {
- execRetry = RETRY_LIMIT; // initialize retry count
- }
-
- done :
-
- if (computerName) CFAllocatorDeallocate(NULL, computerName);
- if (interface) CFAllocatorDeallocate(NULL, interface);
-
- return;
-}
-
-
-static void
-atConfigChangedCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *arg)
-{
- boolean_t configChanged;
- int newState;
-
- configChanged = updateConfiguration(&newState);
-
- if (configChanged && (execCommand == 0)) {
- // if the configuration has changed and we're not already transitioning
- if (newState > 0) {
- if (curState > 0) {
- // already running, restart [with new configuration]
- stopAppleTalk(NULL, (void *)newState);
- } else {
- startAppleTalk(NULL, (void *)newState);
- }
- } else {
- if (curState > 0) {
- stopAppleTalk(NULL, (void *)newState);
- }
- }
- }
-
- curState = newState;
-
- return;
-}
-
-
-void
-stop_ATconfig(CFRunLoopSourceRef stopRls)
-{
- // cleanup
-
- if (storeRls != NULL) {
- CFRunLoopSourceInvalidate(storeRls);
- CFRelease(storeRls);
- storeRls = NULL;
- }
-
- if (store != NULL) {
- CFRelease(store);
- store = NULL;
- CFRelease(curGlobals);
- CFRelease(curConfigFile);
- CFRelease(curDefaults);
- CFRelease(curStartup);
- }
-
- CFRunLoopSourceSignal(stopRls);
- return;
-}
-
-
-void
-load_ATconfig(CFBundleRef bundle, Boolean bundleVerbose)
-{
- CFStringRef key;
- CFMutableArrayRef keys = NULL;
- CFStringRef pattern;
- CFMutableArrayRef patterns = NULL;
-
- if (bundleVerbose) {
- _verbose = TRUE;
- }
-
- SCLog(_verbose, LOG_DEBUG, CFSTR("load() called"));
- SCLog(_verbose, LOG_DEBUG, CFSTR(" bundle ID = %@"), CFBundleGetIdentifier(bundle));
-
- /* initialize a few globals */
-
- curGlobals = CFDictionaryCreateMutable(NULL,
- 0,
- &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks);
- curConfigFile = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
- curDefaults = CFDictionaryCreateMutable(NULL,
- 0,
- &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks);
- curStartup = CFDictionaryCreateMutable(NULL,
- 0,
- &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks);
-
- /* open a "configd" store to allow cache updates */
- store = SCDynamicStoreCreate(NULL,
- CFSTR("AppleTalk Configuraton plug-in"),
- atConfigChangedCallback,
- NULL);
- if (store == NULL) {
- SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreCreate() failed: %s"), SCErrorString(SCError()));
- goto error;
- }
-
- /* establish notification keys and patterns */
-
- keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
- patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
-
- /* ...watch for (global) AppleTalk configuration changes */
- key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL,
- kSCDynamicStoreDomainSetup,
- kSCEntNetAppleTalk);
- CFArrayAppendValue(keys, key);
- CFRelease(key);
-
- /* ...watch for (per-service) AppleTalk configuration changes */
- pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
- kSCDynamicStoreDomainSetup,
- kSCCompAnyRegex,
- kSCEntNetAppleTalk);
- CFArrayAppendValue(patterns, pattern);
- CFRelease(pattern);
-
- /* ...watch for network interface link status changes */
- pattern = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
- kSCDynamicStoreDomainState,
- kSCCompAnyRegex,
- kSCEntNetLink);
- CFArrayAppendValue(patterns, pattern);
- CFRelease(pattern);
-
- /* ...watch for (per-interface) AppleTalk configuration changes */
- pattern = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
- kSCDynamicStoreDomainState,
- kSCCompAnyRegex,
- kSCEntNetAppleTalk);
- CFArrayAppendValue(patterns, pattern);
- CFRelease(pattern);
-
- /* ...watch for computer name changes */
- key = SCDynamicStoreKeyCreateComputerName(NULL);
- CFArrayAppendValue(keys, key);
- CFRelease(key);
-
- /* register the keys/patterns */
- if (!SCDynamicStoreSetNotificationKeys(store, keys, patterns)) {
- SCLog(TRUE, LOG_ERR,
- CFSTR("SCDynamicStoreSetNotificationKeys() failed: %s"),
- SCErrorString(SCError()));
- goto error;
- }
- CFRelease(keys);
- CFRelease(patterns);
-
- storeRls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
- if (!storeRls) {
- SCLog(TRUE, LOG_ERR,
- CFSTR("SCDynamicStoreCreateRunLoopSource() failed: %s"),
- SCErrorString(SCError()));
- goto error;
- }
- CFRunLoopAddSource(CFRunLoopGetCurrent(), storeRls, kCFRunLoopDefaultMode);
-
- return;
-
- error :
-
- if (curGlobals) CFRelease(curGlobals);
- if (curConfigFile) CFRelease(curConfigFile);
- if (curDefaults) CFRelease(curDefaults);
- if (curStartup) CFRelease(curStartup);
- 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_ATconfig(CFBundleGetMainBundle(), (argc > 1) ? TRUE : FALSE);
- CFRunLoopRun();
- /* not reached */
- exit(0);
- return 0;
-}
-#endif