]> git.saurik.com Git - apple/configd.git/blobdiff - Plugins/LinkConfiguration/linkconfig.c
configd-289.tar.gz
[apple/configd.git] / Plugins / LinkConfiguration / linkconfig.c
index 75d7262c4df9b61a424d9fc7efab2d2bda645488..b0d89df0a762d797a0c0c7d0463f1fb6d6834950 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2002-2007 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
 
 
 static CFMutableDictionaryRef  baseSettings    = NULL;
+static CFStringRef             interfacesKey   = NULL;
 static SCDynamicStoreRef       store           = NULL;
 static CFRunLoopSourceRef      rls             = NULL;
+static CFMutableDictionaryRef  wantSettings    = NULL;
 
 static Boolean                 _verbose        = FALSE;
 
 
 /* in SystemConfiguration/LinkConfiguration.c */
 int
-__createMediaOptions(CFDictionaryRef media_options);
+__createMediaOptions(CFStringRef interfaceName, CFDictionaryRef media_options);
+
+
+static CFDictionaryRef
+__copyMediaOptions(CFDictionaryRef options)
+{
+       CFMutableDictionaryRef  requested       = NULL;
+       CFTypeRef               val;
+
+       if (!isA_CFDictionary(options)) {
+               return NULL;
+       }
+
+       val = CFDictionaryGetValue(options, kSCPropNetEthernetMediaSubType);
+       if (isA_CFString(val)) {
+               requested = CFDictionaryCreateMutable(NULL,
+                                                     0,
+                                                     &kCFTypeDictionaryKeyCallBacks,
+                                                     &kCFTypeDictionaryValueCallBacks);
+               CFDictionaryAddValue(requested, kSCPropNetEthernetMediaSubType, val);
+       } else {
+               /* if garbage */;
+               return NULL;
+       }
+
+       val = CFDictionaryGetValue(options, kSCPropNetEthernetMediaOptions);
+       if (isA_CFArray(val)) {
+               CFDictionaryAddValue(requested, kSCPropNetEthernetMediaOptions, val);
+       } else {
+               /* if garbage */;
+               CFRelease(requested);
+               return NULL;
+       }
+
+       return requested;
+}
 
 
 __private_extern__
 Boolean
-_NetworkInterfaceSetMediaOptions(CFStringRef           interface,
-                                CFDictionaryRef        options)
+_SCNetworkInterfaceSetMediaOptions(SCNetworkInterfaceRef       interface,
+                                  CFDictionaryRef              options)
 {
        CFArrayRef              available       = NULL;
        CFDictionaryRef         current         = NULL;
        struct ifmediareq       ifm;
        struct ifreq            ifr;
+       CFStringRef             interfaceName;
        Boolean                 ok              = FALSE;
        int                     newOptions;
-       CFMutableDictionaryRef  requested       = NULL;
+       CFDictionaryRef         requested;
        int                     sock            = -1;
-       CFTypeRef               val;
+
+       interfaceName = SCNetworkInterfaceGetBSDName(interface);
+       if (interfaceName == NULL) {
+               /* if no BSD interface name */
+               SCLog(_verbose, LOG_INFO, CFSTR("no BSD interface name for %@"), interface);
+               return FALSE;
+       }
 
        /* get current & available options */
-       if (!NetworkInterfaceCopyMediaOptions(interface, &current, NULL, &available, FALSE)) {
+       if (!SCNetworkInterfaceCopyMediaOptions(interface, &current, NULL, &available, FALSE)) {
+               /* could not get current media options */
+               SCLog(_verbose, LOG_INFO, CFSTR("no media options for %@"), interfaceName);
                return FALSE;
        }
 
        /* extract just the dictionary key/value pairs of interest */
-       requested = CFDictionaryCreateMutable(NULL,
-                                             0,
-                                             &kCFTypeDictionaryKeyCallBacks,
-                                             &kCFTypeDictionaryValueCallBacks);
+       requested = __copyMediaOptions(options);
+       if (requested == NULL) {
+               CFDictionaryRef baseOptions;
 
-       val = CFDictionaryGetValue(options, kSCPropNetEthernetMediaSubType);
-       if (!val) {
-               val = CFDictionaryGetValue(current, kSCPropNetEthernetMediaSubType);
+               /* get base options */
+               baseOptions = CFDictionaryGetValue(baseSettings, interfaceName);
+               requested = __copyMediaOptions(baseOptions);
        }
-       if (isA_CFString(val)) {
-               CFDictionaryAddValue(requested, kSCPropNetEthernetMediaSubType, val);
-       } else {
-               /* if garbage */;
-               goto done;
+       if (requested == NULL) {
+               /* get base options */
+               requested = __copyMediaOptions(current);
        }
-
-       val = CFDictionaryGetValue(options, kSCPropNetEthernetMediaOptions);
-       if (!val) {
-               val = CFDictionaryGetValue(current, kSCPropNetEthernetMediaOptions);
-       }
-       if (isA_CFArray(val)) {
-               CFDictionaryAddValue(requested, kSCPropNetEthernetMediaOptions, val);
-       } else {
-               /* if garbage */;
+       if (requested == NULL) {
+               /* if no media options to set */
                goto done;
        }
 
-       if (current && CFEqual(current, requested)) {
+       if ((current != NULL) && CFEqual(current, requested)) {
                /* if current settings are as requested */
                ok = TRUE;
                goto done;
@@ -113,26 +149,26 @@ _NetworkInterfaceSetMediaOptions(CFStringRef              interface,
 
        if (!CFArrayContainsValue(available, CFRangeMake(0, CFArrayGetCount(available)), requested)) {
                /* if requested settings not currently available */
-               SCLog(TRUE, LOG_DEBUG, CFSTR("requested media settings unavailable"));
+               SCLog(_verbose, LOG_INFO, CFSTR("requested media settings unavailable for %@"), interfaceName);
                goto done;
        }
 
-       newOptions = __createMediaOptions(requested);
+       newOptions = __createMediaOptions(interfaceName, requested);
        if (newOptions == -1) {
                /* since we have just validated, this should never happen */
                goto done;
        }
 
        sock = socket(AF_INET, SOCK_DGRAM, 0);
-       if (sock < 0) {
+       if (sock == -1) {
                SCLog(TRUE, LOG_ERR, CFSTR("socket() failed: %s"), strerror(errno));
                goto done;
        }
 
        bzero((char *)&ifm, sizeof(ifm));
-       (void)_SC_cfstring_to_cstring(interface, ifm.ifm_name, sizeof(ifm.ifm_name), kCFStringEncodingASCII);
+       (void)_SC_cfstring_to_cstring(interfaceName, ifm.ifm_name, sizeof(ifm.ifm_name), kCFStringEncodingASCII);
 
-       if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifm) < 0) {
+       if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifm) == -1) {
                SCLog(TRUE, LOG_DEBUG, CFSTR("ioctl(SIOCGIFMEDIA) failed: %s"), strerror(errno));
                goto done;
        }
@@ -142,11 +178,11 @@ _NetworkInterfaceSetMediaOptions(CFStringRef              interface,
        ifr.ifr_media =  ifm.ifm_current & ~(IFM_NMASK|IFM_TMASK|IFM_OMASK|IFM_GMASK);
        ifr.ifr_media |= newOptions;
 
-//SCLog(TRUE, LOG_INFO, CFSTR("old media settings: 0x%8.8x (0x%8.8x)"), ifm.ifm_current, ifm.ifm_active);
-//SCLog(TRUE, LOG_INFO, CFSTR("new media settings: 0x%8.8x"), ifr.ifr_media);
+       SCLog(_verbose, LOG_INFO, CFSTR("old media settings: 0x%8.8x (0x%8.8x)"), ifm.ifm_current, ifm.ifm_active);
+       SCLog(_verbose, LOG_INFO, CFSTR("new media settings: 0x%8.8x"), ifr.ifr_media);
 
-       if (ioctl(sock, SIOCSIFMEDIA, (caddr_t)&ifr) < 0) {
-               SCLog(TRUE, LOG_DEBUG, CFSTR("ioctl(SIOCSIFMEDIA) failed: %s"), strerror(errno));
+       if (ioctl(sock, SIOCSIFMEDIA, (caddr_t)&ifr) == -1) {
+               SCLog(TRUE, LOG_DEBUG, CFSTR("%@: ioctl(SIOCSIFMEDIA) failed: %s"), interfaceName, strerror(errno));
                goto done;
        }
 
@@ -154,10 +190,10 @@ _NetworkInterfaceSetMediaOptions(CFStringRef              interface,
 
     done :
 
-       if (available)  CFRelease(available);
-       if (current)    CFRelease(current);
-       if (requested)  CFRelease(requested);
-       if (sock >= 0)  (void)close(sock);
+       if (available != NULL)  CFRelease(available);
+       if (current != NULL)    CFRelease(current);
+       if (requested != NULL)  CFRelease(requested);
+       if (sock != -1) (void)close(sock);
 
        return ok;
 }
@@ -196,27 +232,43 @@ ifconfig_exit(pid_t pid, int status, struct rusage *rusage, void *context)
 
 __private_extern__
 Boolean
-_NetworkInterfaceSetMTU(CFStringRef    interface,
-                       CFDictionaryRef options)
+_SCNetworkInterfaceSetMTU(SCNetworkInterfaceRef        interface,
+                         CFDictionaryRef       options)
 {
+       CFStringRef     interfaceName;
        int             mtu_cur         = -1;
        int             mtu_max         = -1;
        int             mtu_min         = -1;
        int             requested;
        CFNumberRef     val;
 
-       if (!NetworkInterfaceCopyMTU(interface, &mtu_cur, &mtu_min, &mtu_max)) {
+       interfaceName = SCNetworkInterfaceGetBSDName(interface);
+       if (interfaceName == NULL) {
+               /* if no BSD interface name */
+               return FALSE;
+       }
+
+       if (!SCNetworkInterfaceCopyMTU(interface, &mtu_cur, &mtu_min, &mtu_max)) {
                /* could not get current MTU */
                return FALSE;
        }
 
-       val = CFDictionaryGetValue(options, kSCPropNetEthernetMTU);
-       if (val) {
-               if (isA_CFNumber(val)) {
-                       CFNumberGetValue(val, kCFNumberIntType, &requested);
-               } else {
-                       return FALSE;
+       val = NULL;
+       if (isA_CFDictionary(options)) {
+               val = CFDictionaryGetValue(options, kSCPropNetEthernetMTU);
+               val = isA_CFNumber(val);
+       }
+       if (val == NULL) {
+               CFDictionaryRef baseOptions;
+
+               /* get base MTU */
+               baseOptions = CFDictionaryGetValue(baseSettings, interfaceName);
+               if (baseOptions != NULL) {
+                       val = CFDictionaryGetValue(baseOptions, kSCPropNetEthernetMTU);
                }
+       }
+       if (val != NULL) {
+               CFNumberGetValue(val, kCFNumberIntType, &requested);
        } else {
                requested = mtu_cur;
        }
@@ -239,11 +291,11 @@ _NetworkInterfaceSetMTU(CFStringRef       interface,
        int             sock;
 
        bzero((char *)&ifr, sizeof(ifr));
-       (void)_SC_cfstring_to_cstring(interface, ifr.ifr_name, sizeof(ifr.ifr_name), kCFStringEncodingASCII);
+       (void)_SC_cfstring_to_cstring(interfaceName, ifr.ifr_name, sizeof(ifr.ifr_name), kCFStringEncodingASCII);
        ifr.ifr_mtu = requested;
 
        sock = socket(AF_INET, SOCK_DGRAM, 0);
-       if (sock < 0) {
+       if (sock == -1) {
                SCLog(TRUE, LOG_ERR, CFSTR("socket() failed: %s"), strerror(errno));
                return FALSE;
        }
@@ -260,7 +312,7 @@ _NetworkInterfaceSetMTU(CFStringRef interface,
        char    *ifconfig_argv[] = { "ifconfig", NULL, "mtu", NULL, NULL };
        pid_t   pid;
 
-       ifconfig_argv[1] = _SC_cfstring_to_cstring(interface, NULL, 0, kCFStringEncodingASCII);
+       ifconfig_argv[1] = _SC_cfstring_to_cstring(interfaceName, NULL, 0, kCFStringEncodingASCII);
        (void)asprintf(&ifconfig_argv[3], "%d", requested);
 
        pid = _SCDPluginExecCommand(ifconfig_exit,      // callout,
@@ -318,82 +370,114 @@ parse_component(CFStringRef key, CFStringRef prefix)
 }
 
 
+static void updateLink(CFStringRef interfaceName, CFDictionaryRef options);
+
+
 static void
-updateLink(CFStringRef ifKey, CFDictionaryRef options)
+updateInterfaces(CFArrayRef newInterfaces)
 {
-       CFStringRef             interface       = NULL;
-       static CFStringRef      prefix          = NULL;
+       CFIndex                 i;
+       CFIndex                 n_old;
+       CFIndex                 n_new;
+       static CFArrayRef       oldInterfaces   = NULL;
 
-       if (!prefix) {
-               prefix = SCDynamicStoreKeyCreate(NULL,
-                                                CFSTR("%@/%@/%@/"),
-                                                kSCDynamicStoreDomainSetup,
-                                                kSCCompNetwork,
-                                                kSCCompInterface);
+       n_old = (oldInterfaces != NULL) ? CFArrayGetCount(oldInterfaces) : 0;
+       n_new = CFArrayGetCount(newInterfaces);
+
+       for (i = 0; i < n_new; i++) {
+               CFStringRef     interfaceName;
+
+               interfaceName = CFArrayGetValueAtIndex(newInterfaces, i);
+
+               if ((n_old == 0) ||
+                   !CFArrayContainsValue(oldInterfaces,
+                                         CFRangeMake(0, n_old),
+                                         interfaceName)) {
+                       CFDictionaryRef options;
+
+                       // if new interface
+                       options = CFDictionaryGetValue(wantSettings, interfaceName);
+                       updateLink(interfaceName, options);
+               }
        }
 
-       interface = parse_component(ifKey, prefix);
-       if (!interface) {
-               goto done;
+       if (oldInterfaces != NULL) CFRelease(oldInterfaces);
+       oldInterfaces = CFRetain(newInterfaces);
+}
+
+
+static void
+updateLink(CFStringRef interfaceName, CFDictionaryRef options)
+{
+       SCNetworkInterfaceRef   interface;
+
+       /* retain requested configuration */
+       if (options != NULL) {
+               CFDictionarySetValue(wantSettings, interfaceName, options);
+       } else {
+               CFDictionaryRemoveValue(wantSettings, interfaceName);
        }
 
-       if (options) {
-               if (!CFDictionaryContainsKey(baseSettings, interface)) {
+       /* apply requested configuration */
+       interface = _SCNetworkInterfaceCreateWithBSDName(NULL, interfaceName,
+                                                        kIncludeAllVirtualInterfaces);
+       if (interface == NULL) {
+               return;
+       }
+
+       if (options != NULL) {
+               if (!CFDictionaryContainsKey(baseSettings, interfaceName)) {
                        CFDictionaryRef         cur_media       = NULL;
                        CFMutableDictionaryRef  new_media       = NULL;
                        int                     cur_mtu         = -1;
-                       CFNumberRef             num;
-
-                       if (!NetworkInterfaceCopyMediaOptions(interface, &cur_media, NULL, NULL, FALSE)) {
-                               /* could not determine current settings */
-                               goto done;
-                       }
 
-                       if (!cur_media) {
-                               /* could not determine current settings */
-                               goto done;
+                       /* preserve current media options */
+                       if (SCNetworkInterfaceCopyMediaOptions(interface, &cur_media, NULL, NULL, FALSE)) {
+                               if (cur_media != NULL) {
+                                       new_media = CFDictionaryCreateMutableCopy(NULL, 0, cur_media);
+                                       CFRelease(cur_media);
+                               }
                        }
 
-                       if (!NetworkInterfaceCopyMTU(interface, &cur_mtu, NULL, NULL)) {
-                               /* could not determine current MTU */
-                               CFRelease(cur_media);
-                               goto done;
+                       /* preserve current MTU */
+                       if (SCNetworkInterfaceCopyMTU(interface, &cur_mtu, NULL, NULL)) {
+                               if (cur_mtu != -1) {
+                                       CFNumberRef     num;
+
+                                       if (new_media == NULL) {
+                                               new_media = CFDictionaryCreateMutable(NULL,
+                                                                                     0,
+                                                                                     &kCFTypeDictionaryKeyCallBacks,
+                                                                                     &kCFTypeDictionaryValueCallBacks);
+                                       }
+
+                                       num = CFNumberCreate(NULL, kCFNumberIntType, &cur_mtu);
+                                       CFDictionaryAddValue(new_media, kSCPropNetEthernetMTU, num);
+                                       CFRelease(num);
+                               }
                        }
 
-                       if (cur_mtu < 0) {
-                               /* could not determine current MTU */
-                               CFRelease(cur_media);
-                               goto done;
+                       if (new_media != NULL) {
+                               CFDictionarySetValue(baseSettings, interfaceName, new_media);
+                               CFRelease(new_media);
                        }
-
-                       new_media = CFDictionaryCreateMutableCopy(NULL, 0, cur_media);
-                       CFRelease(cur_media);
-
-                       num = CFNumberCreate(NULL, kCFNumberIntType, &cur_mtu);
-                       CFDictionaryAddValue(new_media, kSCPropNetEthernetMTU, num);
-                       CFRelease(num);
-
-                       CFDictionarySetValue(baseSettings, interface, new_media);
-                       CFRelease(new_media);
                }
 
                /* establish new settings */
-               (void)_NetworkInterfaceSetMediaOptions(interface, options);
-               (void)_NetworkInterfaceSetMTU         (interface, options);
+               (void)_SCNetworkInterfaceSetMediaOptions(interface, options);
+               (void)_SCNetworkInterfaceSetMTU         (interface, options);
        } else {
                /* no requested settings */
-               options = CFDictionaryGetValue(baseSettings, interface);
-               if (options) {
+               options = CFDictionaryGetValue(baseSettings, interfaceName);
+               if (options != NULL) {
                        /* restore original settings */
-                       (void)_NetworkInterfaceSetMediaOptions(interface, options);
-                       (void)_NetworkInterfaceSetMTU         (interface, options);
-                       CFDictionaryRemoveValue(baseSettings, interface);
+                       (void)_SCNetworkInterfaceSetMediaOptions(interface, options);
+                       (void)_SCNetworkInterfaceSetMTU         (interface, options);
+                       CFDictionaryRemoveValue(baseSettings, interfaceName);
                }
        }
 
-    done :
-
-       if (interface)  CFRelease(interface);
+       CFRelease(interface);
        return;
 }
 
@@ -401,23 +485,48 @@ updateLink(CFStringRef ifKey, CFDictionaryRef options)
 static void
 linkConfigChangedCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *arg)
 {
+       CFDictionaryRef         changes;
        CFIndex                 i;
        CFIndex                 n;
-       CFDictionaryRef         linkInfo;
+       static CFStringRef      prefix          = NULL;
+
+       if (prefix == NULL) {
+               prefix = SCDynamicStoreKeyCreate(NULL,
+                                                CFSTR("%@/%@/%@/"),
+                                                kSCDynamicStoreDomainSetup,
+                                                kSCCompNetwork,
+                                                kSCCompInterface);
+       }
 
-       linkInfo = SCDynamicStoreCopyMultiple(store, changedKeys, NULL);
+       changes = SCDynamicStoreCopyMultiple(store, changedKeys, NULL);
 
        n = CFArrayGetCount(changedKeys);
        for (i = 0; i < n; i++) {
                CFStringRef     key;
-               CFDictionaryRef link;
+               CFDictionaryRef info;
 
                key  = CFArrayGetValueAtIndex(changedKeys, i);
-               link = CFDictionaryGetValue(linkInfo, key);
-               updateLink(key, link);
+               info = CFDictionaryGetValue(changes, key);
+
+               if (CFEqual(key, interfacesKey)) {
+                       CFArrayRef      interfaces;
+
+                       interfaces = CFDictionaryGetValue(info, kSCPropNetInterfaces);
+                       if (isA_CFArray(interfaces)) {
+                               updateInterfaces(interfaces);
+                       }
+               } else {
+                       CFStringRef     interfaceName;
+
+                       interfaceName = parse_component(key, prefix);
+                       if (interfaceName != NULL) {
+                               updateLink(interfaceName, info);
+                               CFRelease(interfaceName);
+                       }
+               }
        }
 
-       CFRelease(linkInfo);
+       CFRelease(changes);
 
        return;
 }
@@ -428,6 +537,8 @@ void
 load_LinkConfiguration(CFBundleRef bundle, Boolean bundleVerbose)
 {
        CFStringRef             key;
+       CFMutableArrayRef       keys            = NULL;
+       Boolean                 ok;
        CFMutableArrayRef       patterns        = NULL;
 
        if (bundleVerbose) {
@@ -443,21 +554,38 @@ load_LinkConfiguration(CFBundleRef bundle, Boolean bundleVerbose)
                                                 0,
                                                 &kCFTypeDictionaryKeyCallBacks,
                                                 &kCFTypeDictionaryValueCallBacks);
+       wantSettings = CFDictionaryCreateMutable(NULL,
+                                                0,
+                                                &kCFTypeDictionaryKeyCallBacks,
+                                                &kCFTypeDictionaryValueCallBacks);
 
        /* open a "configd" store to allow cache updates */
        store = SCDynamicStoreCreate(NULL,
                                     CFSTR("Link Configuraton plug-in"),
                                     linkConfigChangedCallback,
                                     NULL);
-       if (!store) {
+       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 a change in the list of network interfaces */
+       interfacesKey = SCDynamicStoreKeyCreateNetworkInterface(NULL,
+                                                               kSCDynamicStoreDomainState);
+       CFArrayAppendValue(keys, interfacesKey);
+
+       /* ...watch for (per-interface) AirPort configuration changes */
+       key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
+                                                           kSCDynamicStoreDomainSetup,
+                                                           kSCCompAnyRegex,
+                                                           kSCEntNetAirPort);
+       CFArrayAppendValue(patterns, key);
+       CFRelease(key);
+
        /* ...watch for (per-interface) Ethernet configuration changes */
        key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
                                                            kSCDynamicStoreDomainSetup,
@@ -466,8 +594,19 @@ load_LinkConfiguration(CFBundleRef bundle, Boolean bundleVerbose)
        CFArrayAppendValue(patterns, key);
        CFRelease(key);
 
+       /* ...watch for (per-interface) FireWire configuration changes */
+       key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
+                                                           kSCDynamicStoreDomainSetup,
+                                                           kSCCompAnyRegex,
+                                                           kSCEntNetFireWire);
+       CFArrayAppendValue(patterns, key);
+       CFRelease(key);
+
        /* register the keys/patterns */
-       if (!SCDynamicStoreSetNotificationKeys(store, NULL, patterns)) {
+       ok = SCDynamicStoreSetNotificationKeys(store, keys, patterns);
+       CFRelease(keys);
+       CFRelease(patterns);
+       if (!ok) {
                SCLog(TRUE, LOG_ERR,
                      CFSTR("SCDynamicStoreSetNotificationKeys() failed: %s"),
                      SCErrorString(SCError()));
@@ -475,7 +614,7 @@ load_LinkConfiguration(CFBundleRef bundle, Boolean bundleVerbose)
        }
 
        rls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
-       if (!rls) {
+       if (rls == NULL) {
                SCLog(TRUE, LOG_ERR,
                      CFSTR("SCDynamicStoreCreateRunLoopSource() failed: %s"),
                      SCErrorString(SCError()));
@@ -483,15 +622,13 @@ load_LinkConfiguration(CFBundleRef bundle, Boolean bundleVerbose)
        }
 
        CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
-
-       CFRelease(patterns);
        return;
 
     error :
 
-       if (baseSettings)       CFRelease(baseSettings);
-       if (store)              CFRelease(store);
-       if (patterns)           CFRelease(patterns);
+       if (baseSettings != NULL)       CFRelease(baseSettings);
+       if (wantSettings != NULL)       CFRelease(wantSettings);
+       if (store != NULL)              CFRelease(store);
        return;
 }