]> git.saurik.com Git - apple/configd.git/blame - Plugins/LinkConfiguration/linkconfig.c
configd-289.tar.gz
[apple/configd.git] / Plugins / LinkConfiguration / linkconfig.c
CommitLineData
dbf6a266 1/*
edebe297 2 * Copyright (c) 2002-2007 Apple Inc. All rights reserved.
dbf6a266
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24/*
25 * Modification History
26 *
27 * October 21, 2000 Allan Nathanson <ajn@apple.com>
28 * - initial revision
29 */
30
31
32#include <stdio.h>
33#include <unistd.h>
34//#include <sys/fcntl.h>
35#include <sys/ioctl.h>
36#include <sys/socket.h>
37#include <sys/wait.h>
38#include <net/if.h>
39#include <net/if_media.h>
40
41#include <SystemConfiguration/SystemConfiguration.h>
42#include <SystemConfiguration/SCPrivate.h>
43#include <SystemConfiguration/SCValidation.h>
44#include <SystemConfiguration/LinkConfiguration.h>
45#include <SystemConfiguration/SCDPlugin.h> // for _SCDPluginExecCommand
46
47
48static CFMutableDictionaryRef baseSettings = NULL;
edebe297 49static CFStringRef interfacesKey = NULL;
dbf6a266
A
50static SCDynamicStoreRef store = NULL;
51static CFRunLoopSourceRef rls = NULL;
edebe297 52static CFMutableDictionaryRef wantSettings = NULL;
dbf6a266
A
53
54static Boolean _verbose = FALSE;
55
56
57/* in SystemConfiguration/LinkConfiguration.c */
58int
edebe297 59__createMediaOptions(CFStringRef interfaceName, CFDictionaryRef media_options);
d6c893b2
A
60
61
62static CFDictionaryRef
63__copyMediaOptions(CFDictionaryRef options)
64{
65 CFMutableDictionaryRef requested = NULL;
66 CFTypeRef val;
67
68 if (!isA_CFDictionary(options)) {
69 return NULL;
70 }
71
72 val = CFDictionaryGetValue(options, kSCPropNetEthernetMediaSubType);
73 if (isA_CFString(val)) {
74 requested = CFDictionaryCreateMutable(NULL,
75 0,
76 &kCFTypeDictionaryKeyCallBacks,
77 &kCFTypeDictionaryValueCallBacks);
78 CFDictionaryAddValue(requested, kSCPropNetEthernetMediaSubType, val);
79 } else {
80 /* if garbage */;
81 return NULL;
82 }
83
84 val = CFDictionaryGetValue(options, kSCPropNetEthernetMediaOptions);
85 if (isA_CFArray(val)) {
86 CFDictionaryAddValue(requested, kSCPropNetEthernetMediaOptions, val);
87 } else {
88 /* if garbage */;
89 CFRelease(requested);
90 return NULL;
91 }
92
93 return requested;
94}
dbf6a266
A
95
96
97__private_extern__
98Boolean
edebe297
A
99_SCNetworkInterfaceSetMediaOptions(SCNetworkInterfaceRef interface,
100 CFDictionaryRef options)
dbf6a266
A
101{
102 CFArrayRef available = NULL;
103 CFDictionaryRef current = NULL;
104 struct ifmediareq ifm;
105 struct ifreq ifr;
edebe297 106 CFStringRef interfaceName;
dbf6a266
A
107 Boolean ok = FALSE;
108 int newOptions;
d6c893b2 109 CFDictionaryRef requested;
dbf6a266 110 int sock = -1;
dbf6a266 111
edebe297
A
112 interfaceName = SCNetworkInterfaceGetBSDName(interface);
113 if (interfaceName == NULL) {
114 /* if no BSD interface name */
115 SCLog(_verbose, LOG_INFO, CFSTR("no BSD interface name for %@"), interface);
116 return FALSE;
117 }
118
dbf6a266 119 /* get current & available options */
edebe297 120 if (!SCNetworkInterfaceCopyMediaOptions(interface, &current, NULL, &available, FALSE)) {
d6c893b2 121 /* could not get current media options */
edebe297 122 SCLog(_verbose, LOG_INFO, CFSTR("no media options for %@"), interfaceName);
dbf6a266
A
123 return FALSE;
124 }
125
126 /* extract just the dictionary key/value pairs of interest */
d6c893b2
A
127 requested = __copyMediaOptions(options);
128 if (requested == NULL) {
129 CFDictionaryRef baseOptions;
dbf6a266 130
d6c893b2 131 /* get base options */
edebe297 132 baseOptions = CFDictionaryGetValue(baseSettings, interfaceName);
d6c893b2 133 requested = __copyMediaOptions(baseOptions);
dbf6a266 134 }
d6c893b2
A
135 if (requested == NULL) {
136 /* get base options */
137 requested = __copyMediaOptions(current);
dbf6a266 138 }
d6c893b2
A
139 if (requested == NULL) {
140 /* if no media options to set */
dbf6a266
A
141 goto done;
142 }
143
d6c893b2 144 if ((current != NULL) && CFEqual(current, requested)) {
dbf6a266
A
145 /* if current settings are as requested */
146 ok = TRUE;
147 goto done;
148 }
149
150 if (!CFArrayContainsValue(available, CFRangeMake(0, CFArrayGetCount(available)), requested)) {
151 /* if requested settings not currently available */
edebe297 152 SCLog(_verbose, LOG_INFO, CFSTR("requested media settings unavailable for %@"), interfaceName);
dbf6a266
A
153 goto done;
154 }
155
edebe297 156 newOptions = __createMediaOptions(interfaceName, requested);
dbf6a266
A
157 if (newOptions == -1) {
158 /* since we have just validated, this should never happen */
159 goto done;
160 }
161
162 sock = socket(AF_INET, SOCK_DGRAM, 0);
edebe297 163 if (sock == -1) {
dbf6a266
A
164 SCLog(TRUE, LOG_ERR, CFSTR("socket() failed: %s"), strerror(errno));
165 goto done;
166 }
167
168 bzero((char *)&ifm, sizeof(ifm));
edebe297 169 (void)_SC_cfstring_to_cstring(interfaceName, ifm.ifm_name, sizeof(ifm.ifm_name), kCFStringEncodingASCII);
dbf6a266 170
edebe297 171 if (ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifm) == -1) {
dbf6a266
A
172 SCLog(TRUE, LOG_DEBUG, CFSTR("ioctl(SIOCGIFMEDIA) failed: %s"), strerror(errno));
173 goto done;
174 }
175
176 bzero((char *)&ifr, sizeof(ifr));
177 bcopy(ifm.ifm_name, ifr.ifr_name, sizeof(ifr.ifr_name));
178 ifr.ifr_media = ifm.ifm_current & ~(IFM_NMASK|IFM_TMASK|IFM_OMASK|IFM_GMASK);
179 ifr.ifr_media |= newOptions;
180
edebe297
A
181 SCLog(_verbose, LOG_INFO, CFSTR("old media settings: 0x%8.8x (0x%8.8x)"), ifm.ifm_current, ifm.ifm_active);
182 SCLog(_verbose, LOG_INFO, CFSTR("new media settings: 0x%8.8x"), ifr.ifr_media);
dbf6a266 183
edebe297
A
184 if (ioctl(sock, SIOCSIFMEDIA, (caddr_t)&ifr) == -1) {
185 SCLog(TRUE, LOG_DEBUG, CFSTR("%@: ioctl(SIOCSIFMEDIA) failed: %s"), interfaceName, strerror(errno));
dbf6a266
A
186 goto done;
187 }
188
189 ok = TRUE;
190
191 done :
192
edebe297
A
193 if (available != NULL) CFRelease(available);
194 if (current != NULL) CFRelease(current);
195 if (requested != NULL) CFRelease(requested);
196 if (sock != -1) (void)close(sock);
dbf6a266
A
197
198 return ok;
199}
200
201
202#ifndef USE_SIOCSIFMTU
203static void
204ifconfig_exit(pid_t pid, int status, struct rusage *rusage, void *context)
205{
206 char *if_name = (char *)context;
207
208 if (WIFEXITED(status)) {
209 if (WEXITSTATUS(status) != 0) {
210 SCLog(TRUE, LOG_ERR,
211 CFSTR("ifconfig %s failed, exit status = %d"),
212 if_name,
213 WEXITSTATUS(status));
214 }
215 } else if (WIFSIGNALED(status)) {
216 SCLog(TRUE, LOG_DEBUG,
217 CFSTR("ifconfig %s: terminated w/signal = %d"),
218 if_name,
219 WTERMSIG(status));
220 } else {
221 SCLog(TRUE, LOG_DEBUG,
222 CFSTR("ifconfig %s: exit status = %d"),
223 if_name,
224 status);
225 }
226
227 CFAllocatorDeallocate(NULL, if_name);
228 return;
229}
230#endif /* !USE_SIOCSIFMTU */
231
232
233__private_extern__
234Boolean
edebe297
A
235_SCNetworkInterfaceSetMTU(SCNetworkInterfaceRef interface,
236 CFDictionaryRef options)
dbf6a266 237{
edebe297 238 CFStringRef interfaceName;
dbf6a266
A
239 int mtu_cur = -1;
240 int mtu_max = -1;
241 int mtu_min = -1;
242 int requested;
243 CFNumberRef val;
244
edebe297
A
245 interfaceName = SCNetworkInterfaceGetBSDName(interface);
246 if (interfaceName == NULL) {
247 /* if no BSD interface name */
248 return FALSE;
249 }
250
251 if (!SCNetworkInterfaceCopyMTU(interface, &mtu_cur, &mtu_min, &mtu_max)) {
dbf6a266
A
252 /* could not get current MTU */
253 return FALSE;
254 }
255
d6c893b2
A
256 val = NULL;
257 if (isA_CFDictionary(options)) {
258 val = CFDictionaryGetValue(options, kSCPropNetEthernetMTU);
259 val = isA_CFNumber(val);
260 }
261 if (val == NULL) {
262 CFDictionaryRef baseOptions;
263
264 /* get base MTU */
edebe297 265 baseOptions = CFDictionaryGetValue(baseSettings, interfaceName);
d6c893b2
A
266 if (baseOptions != NULL) {
267 val = CFDictionaryGetValue(baseOptions, kSCPropNetEthernetMTU);
dbf6a266 268 }
d6c893b2
A
269 }
270 if (val != NULL) {
271 CFNumberGetValue(val, kCFNumberIntType, &requested);
dbf6a266
A
272 } else {
273 requested = mtu_cur;
274 }
275
276 if (requested == mtu_cur) {
277 /* if current setting is as requested */
278 return TRUE;
279 }
280
281 if (((mtu_min >= 0) && (requested < mtu_min)) ||
282 ((mtu_max >= 0) && (requested > mtu_max))) {
283 /* if requested MTU outside of the valid range */
284 return FALSE;
285 }
286
287#ifdef USE_SIOCSIFMTU
288{
289 struct ifreq ifr;
290 int ret;
291 int sock;
292
293 bzero((char *)&ifr, sizeof(ifr));
edebe297 294 (void)_SC_cfstring_to_cstring(interfaceName, ifr.ifr_name, sizeof(ifr.ifr_name), kCFStringEncodingASCII);
dbf6a266
A
295 ifr.ifr_mtu = requested;
296
297 sock = socket(AF_INET, SOCK_DGRAM, 0);
edebe297 298 if (sock == -1) {
dbf6a266
A
299 SCLog(TRUE, LOG_ERR, CFSTR("socket() failed: %s"), strerror(errno));
300 return FALSE;
301 }
302
303 ret = ioctl(sock, SIOCSIFMTU, (caddr_t)&ifr);
304 (void)close(sock);
305 if (ret == -1) {
306 SCLog(TRUE, LOG_DEBUG, CFSTR("ioctl(SIOCSIFMTU) failed: %s"), strerror(errno));
307 return FALSE;
308 }
309}
310#else /* !USE_SIOCSIFMTU */
311{
312 char *ifconfig_argv[] = { "ifconfig", NULL, "mtu", NULL, NULL };
313 pid_t pid;
314
edebe297 315 ifconfig_argv[1] = _SC_cfstring_to_cstring(interfaceName, NULL, 0, kCFStringEncodingASCII);
dbf6a266
A
316 (void)asprintf(&ifconfig_argv[3], "%d", requested);
317
318 pid = _SCDPluginExecCommand(ifconfig_exit, // callout,
319 ifconfig_argv[1], // context
320 0, // uid
321 0, // gid
322 "/sbin/ifconfig", // path
323 ifconfig_argv // argv
324 );
325
326// CFAllocatorDeallocate(NULL, ifconfig_argv[1]); // released in ifconfig_exit()
327 free(ifconfig_argv[3]);
328
329 if (pid <= 0) {
330 return FALSE;
331 }
332}
333#endif /* !USE_SIOCSIFMTU */
334
335 return TRUE;
336}
337
338
339/*
340 * Function: parse_component
341 * Purpose:
342 * Given a string 'key' and a string prefix 'prefix',
343 * return the next component in the slash '/' separated
344 * key.
345 *
346 * Examples:
347 * 1. key = "a/b/c" prefix = "a/"
348 * returns "b"
349 * 2. key = "a/b/c" prefix = "a/b/"
350 * returns "c"
351 */
352static CFStringRef
353parse_component(CFStringRef key, CFStringRef prefix)
354{
355 CFMutableStringRef comp;
356 CFRange range;
357
358 if (CFStringHasPrefix(key, prefix) == FALSE) {
359 return NULL;
360 }
361 comp = CFStringCreateMutableCopy(NULL, 0, key);
362 CFStringDelete(comp, CFRangeMake(0, CFStringGetLength(prefix)));
363 range = CFStringFind(comp, CFSTR("/"), 0);
364 if (range.location == kCFNotFound) {
365 return comp;
366 }
367 range.length = CFStringGetLength(comp) - range.location;
368 CFStringDelete(comp, range);
369 return comp;
370}
371
372
edebe297
A
373static void updateLink(CFStringRef interfaceName, CFDictionaryRef options);
374
375
dbf6a266 376static void
edebe297 377updateInterfaces(CFArrayRef newInterfaces)
dbf6a266 378{
edebe297
A
379 CFIndex i;
380 CFIndex n_old;
381 CFIndex n_new;
382 static CFArrayRef oldInterfaces = NULL;
dbf6a266 383
edebe297
A
384 n_old = (oldInterfaces != NULL) ? CFArrayGetCount(oldInterfaces) : 0;
385 n_new = CFArrayGetCount(newInterfaces);
386
387 for (i = 0; i < n_new; i++) {
388 CFStringRef interfaceName;
389
390 interfaceName = CFArrayGetValueAtIndex(newInterfaces, i);
391
392 if ((n_old == 0) ||
393 !CFArrayContainsValue(oldInterfaces,
394 CFRangeMake(0, n_old),
395 interfaceName)) {
396 CFDictionaryRef options;
397
398 // if new interface
399 options = CFDictionaryGetValue(wantSettings, interfaceName);
400 updateLink(interfaceName, options);
401 }
dbf6a266
A
402 }
403
edebe297
A
404 if (oldInterfaces != NULL) CFRelease(oldInterfaces);
405 oldInterfaces = CFRetain(newInterfaces);
406}
407
408
409static void
410updateLink(CFStringRef interfaceName, CFDictionaryRef options)
411{
412 SCNetworkInterfaceRef interface;
413
414 /* retain requested configuration */
415 if (options != NULL) {
416 CFDictionarySetValue(wantSettings, interfaceName, options);
417 } else {
418 CFDictionaryRemoveValue(wantSettings, interfaceName);
419 }
420
421 /* apply requested configuration */
422 interface = _SCNetworkInterfaceCreateWithBSDName(NULL, interfaceName,
423 kIncludeAllVirtualInterfaces);
424 if (interface == NULL) {
425 return;
dbf6a266
A
426 }
427
edebe297
A
428 if (options != NULL) {
429 if (!CFDictionaryContainsKey(baseSettings, interfaceName)) {
dbf6a266
A
430 CFDictionaryRef cur_media = NULL;
431 CFMutableDictionaryRef new_media = NULL;
432 int cur_mtu = -1;
dbf6a266 433
d6c893b2 434 /* preserve current media options */
edebe297 435 if (SCNetworkInterfaceCopyMediaOptions(interface, &cur_media, NULL, NULL, FALSE)) {
d6c893b2
A
436 if (cur_media != NULL) {
437 new_media = CFDictionaryCreateMutableCopy(NULL, 0, cur_media);
438 CFRelease(cur_media);
439 }
dbf6a266
A
440 }
441
d6c893b2 442 /* preserve current MTU */
edebe297 443 if (SCNetworkInterfaceCopyMTU(interface, &cur_mtu, NULL, NULL)) {
d6c893b2
A
444 if (cur_mtu != -1) {
445 CFNumberRef num;
446
447 if (new_media == NULL) {
448 new_media = CFDictionaryCreateMutable(NULL,
449 0,
450 &kCFTypeDictionaryKeyCallBacks,
451 &kCFTypeDictionaryValueCallBacks);
452 }
453
454 num = CFNumberCreate(NULL, kCFNumberIntType, &cur_mtu);
455 CFDictionaryAddValue(new_media, kSCPropNetEthernetMTU, num);
456 CFRelease(num);
457 }
dbf6a266
A
458 }
459
d6c893b2 460 if (new_media != NULL) {
edebe297 461 CFDictionarySetValue(baseSettings, interfaceName, new_media);
d6c893b2 462 CFRelease(new_media);
dbf6a266 463 }
dbf6a266
A
464 }
465
466 /* establish new settings */
edebe297
A
467 (void)_SCNetworkInterfaceSetMediaOptions(interface, options);
468 (void)_SCNetworkInterfaceSetMTU (interface, options);
dbf6a266
A
469 } else {
470 /* no requested settings */
edebe297
A
471 options = CFDictionaryGetValue(baseSettings, interfaceName);
472 if (options != NULL) {
dbf6a266 473 /* restore original settings */
edebe297
A
474 (void)_SCNetworkInterfaceSetMediaOptions(interface, options);
475 (void)_SCNetworkInterfaceSetMTU (interface, options);
476 CFDictionaryRemoveValue(baseSettings, interfaceName);
dbf6a266
A
477 }
478 }
479
edebe297 480 CFRelease(interface);
dbf6a266
A
481 return;
482}
483
484
485static void
486linkConfigChangedCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *arg)
487{
edebe297 488 CFDictionaryRef changes;
dbf6a266
A
489 CFIndex i;
490 CFIndex n;
edebe297
A
491 static CFStringRef prefix = NULL;
492
493 if (prefix == NULL) {
494 prefix = SCDynamicStoreKeyCreate(NULL,
495 CFSTR("%@/%@/%@/"),
496 kSCDynamicStoreDomainSetup,
497 kSCCompNetwork,
498 kSCCompInterface);
499 }
dbf6a266 500
edebe297 501 changes = SCDynamicStoreCopyMultiple(store, changedKeys, NULL);
dbf6a266
A
502
503 n = CFArrayGetCount(changedKeys);
504 for (i = 0; i < n; i++) {
505 CFStringRef key;
edebe297 506 CFDictionaryRef info;
dbf6a266
A
507
508 key = CFArrayGetValueAtIndex(changedKeys, i);
edebe297
A
509 info = CFDictionaryGetValue(changes, key);
510
511 if (CFEqual(key, interfacesKey)) {
512 CFArrayRef interfaces;
513
514 interfaces = CFDictionaryGetValue(info, kSCPropNetInterfaces);
515 if (isA_CFArray(interfaces)) {
516 updateInterfaces(interfaces);
517 }
518 } else {
519 CFStringRef interfaceName;
520
521 interfaceName = parse_component(key, prefix);
522 if (interfaceName != NULL) {
523 updateLink(interfaceName, info);
524 CFRelease(interfaceName);
525 }
526 }
dbf6a266
A
527 }
528
edebe297 529 CFRelease(changes);
dbf6a266
A
530
531 return;
532}
533
534
535__private_extern__
536void
537load_LinkConfiguration(CFBundleRef bundle, Boolean bundleVerbose)
538{
539 CFStringRef key;
edebe297
A
540 CFMutableArrayRef keys = NULL;
541 Boolean ok;
dbf6a266
A
542 CFMutableArrayRef patterns = NULL;
543
544 if (bundleVerbose) {
545 _verbose = TRUE;
546 }
547
548 SCLog(_verbose, LOG_DEBUG, CFSTR("load() called"));
549 SCLog(_verbose, LOG_DEBUG, CFSTR(" bundle ID = %@"), CFBundleGetIdentifier(bundle));
550
551 /* initialize a few globals */
552
553 baseSettings = CFDictionaryCreateMutable(NULL,
554 0,
555 &kCFTypeDictionaryKeyCallBacks,
556 &kCFTypeDictionaryValueCallBacks);
edebe297
A
557 wantSettings = CFDictionaryCreateMutable(NULL,
558 0,
559 &kCFTypeDictionaryKeyCallBacks,
560 &kCFTypeDictionaryValueCallBacks);
dbf6a266
A
561
562 /* open a "configd" store to allow cache updates */
563 store = SCDynamicStoreCreate(NULL,
564 CFSTR("Link Configuraton plug-in"),
565 linkConfigChangedCallback,
566 NULL);
edebe297 567 if (store == NULL) {
dbf6a266
A
568 SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreCreate() failed: %s"), SCErrorString(SCError()));
569 goto error;
570 }
571
572 /* establish notification keys and patterns */
edebe297 573 keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
dbf6a266
A
574 patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
575
edebe297
A
576 /* ...watch for a change in the list of network interfaces */
577 interfacesKey = SCDynamicStoreKeyCreateNetworkInterface(NULL,
578 kSCDynamicStoreDomainState);
579 CFArrayAppendValue(keys, interfacesKey);
580
d6c893b2
A
581 /* ...watch for (per-interface) AirPort configuration changes */
582 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
583 kSCDynamicStoreDomainSetup,
584 kSCCompAnyRegex,
585 kSCEntNetAirPort);
586 CFArrayAppendValue(patterns, key);
587 CFRelease(key);
588
dbf6a266
A
589 /* ...watch for (per-interface) Ethernet configuration changes */
590 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
591 kSCDynamicStoreDomainSetup,
592 kSCCompAnyRegex,
593 kSCEntNetEthernet);
594 CFArrayAppendValue(patterns, key);
595 CFRelease(key);
596
d6c893b2
A
597 /* ...watch for (per-interface) FireWire configuration changes */
598 key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL,
599 kSCDynamicStoreDomainSetup,
600 kSCCompAnyRegex,
601 kSCEntNetFireWire);
602 CFArrayAppendValue(patterns, key);
603 CFRelease(key);
604
dbf6a266 605 /* register the keys/patterns */
edebe297
A
606 ok = SCDynamicStoreSetNotificationKeys(store, keys, patterns);
607 CFRelease(keys);
608 CFRelease(patterns);
609 if (!ok) {
dbf6a266
A
610 SCLog(TRUE, LOG_ERR,
611 CFSTR("SCDynamicStoreSetNotificationKeys() failed: %s"),
612 SCErrorString(SCError()));
613 goto error;
614 }
615
616 rls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
edebe297 617 if (rls == NULL) {
dbf6a266
A
618 SCLog(TRUE, LOG_ERR,
619 CFSTR("SCDynamicStoreCreateRunLoopSource() failed: %s"),
620 SCErrorString(SCError()));
621 goto error;
622 }
623
624 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
dbf6a266
A
625 return;
626
627 error :
628
edebe297
A
629 if (baseSettings != NULL) CFRelease(baseSettings);
630 if (wantSettings != NULL) CFRelease(wantSettings);
631 if (store != NULL) CFRelease(store);
dbf6a266
A
632 return;
633}
634
635
636#ifdef MAIN
637int
638main(int argc, char **argv)
639{
640 _sc_log = FALSE;
641 _sc_verbose = (argc > 1) ? TRUE : FALSE;
642
643 load_LinkConfiguration(CFBundleGetMainBundle(), (argc > 1) ? TRUE : FALSE);
644 CFRunLoopRun();
645 /* not reached */
646 exit(0);
647 return 0;
648}
649#endif