1/*
2 * Copyright (c) 2000-2008, 2010, 2012 Apple Inc. All rights reserved.
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 * April 2, 2004		Allan Nathanson <ajn@apple.com>
28 * - use SCPreference notification APIs
29 *
30 * June 24, 2001		Allan Nathanson <ajn@apple.com>
31 * - update to public SystemConfiguration.framework APIs
32 *
33 * November 10, 2000		Allan Nathanson <ajn@apple.com>
34 * - initial revision
35 */
36
37
38#include <TargetConditionals.h>
39#include <fcntl.h>
40#include <sys/types.h>
41#include <sys/stat.h>
42#include <unistd.h>
43
44
45#include <SystemConfiguration/SystemConfiguration.h>
46#include <SystemConfiguration/SCPrivate.h>
47#include <SystemConfiguration/SCValidation.h>
48
49
50
51
52/* globals */
53static SCPreferencesRef		prefs		= NULL;
54static SCDynamicStoreRef	store		= NULL;
55
56/* preferences "initialization" globals */
57static CFStringRef		initKey		= NULL;
58static CFRunLoopSourceRef	initRls		= NULL;
59
60/* SCDynamicStore (Setup:) */
61static CFMutableDictionaryRef	currentPrefs;		/* current prefs */
62static CFMutableDictionaryRef	newPrefs;		/* new prefs */
63static CFMutableArrayRef	unchangedPrefsKeys;	/* new prefs keys which match current */
64static CFMutableArrayRef	removedPrefsKeys;	/* old prefs keys to be removed */
65
66static Boolean			rofs		= FALSE;
67static Boolean			_verbose	= FALSE;
68
69
70static Boolean
71establishNewPreferences()
72{
73	CFBundleRef     bundle;
74	SCNetworkSetRef	current		= NULL;
75	CFStringRef	new_model;
76	Boolean		ok		= FALSE;
77	int		sc_status	= kSCStatusFailed;
78	SCNetworkSetRef	set		= NULL;
79	CFStringRef	setName		= NULL;
80	Boolean		updated		= FALSE;
81
82	while (TRUE) {
83		ok = SCPreferencesLock(prefs, TRUE);
84		if (ok) {
85			break;
86		}
87
88		sc_status = SCError();
89		if (sc_status == kSCStatusStale) {
90			SCPreferencesSynchronize(prefs);
91		} else {
92			SCLog(TRUE, LOG_ERR,
93			      CFSTR("Could not acquire network configuration lock: %s"),
94			      SCErrorString(sc_status));
95			return FALSE;
96		}
97	}
98
99	/* Ensure that the preferences has the new model */
100	new_model = _SC_hw_model();
101
102	/* Need to regenerate the new configuration for new model */
103	if (new_model != NULL) {
104		CFStringRef	old_model;
105
106		old_model = SCPreferencesGetValue(prefs, MODEL);
107		if ((old_model != NULL) && !_SC_CFEqual(old_model, new_model)) {
108			CFIndex		count;
109			CFIndex		index;
110			CFArrayRef	keys;
111
112			keys = SCPreferencesCopyKeyList(prefs);
113			count = (keys != NULL) ? CFArrayGetCount(keys) : 0;
114			// if new hardware
115			for (index = 0; index < count; index++) {
116				CFStringRef		existing_key;
117
118				existing_key = CFArrayGetValueAtIndex(keys, index);
119
120				if (isA_CFString(existing_key) != NULL) {
121					CFStringRef		new_key;
122					CFPropertyListRef	value;
123
124					/* If it already contains a Model
125					   or if it already contains a MODEL:KEY key skip it*/
126					if (CFEqual(existing_key, MODEL)
127					    || CFStringFind(existing_key, CFSTR(":"), 0).location
128					    != kCFNotFound) {
129						continue;
130					}
131
132					value = SCPreferencesGetValue(prefs, existing_key);
133
134					/* Create a new key as OLD_MODEL:OLD_KEY */
135					new_key = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@:%@"),
136									   old_model, existing_key);
137					SCPreferencesSetValue(prefs, new_key, value);
138
139					/* Let's preserve existing host names */
140					if (!CFEqual(existing_key, kSCPrefSystem)) {
141						SCPreferencesRemoveValue(prefs, existing_key);
142					}
143					CFRelease(new_key);
144				}
145			}
146
147			if (keys != NULL) {
148				CFRelease(keys);
149			}
150		}
151		/* Set the new model */
152		SCPreferencesSetValue(prefs, MODEL, new_model);
153	}
154
155	current = SCNetworkSetCopyCurrent(prefs);
156	if (current != NULL) {
157		set = current;
158	}
159
160	if (set == NULL) {
161		set = SCNetworkSetCreate(prefs);
162		if (set == NULL) {
163			ok = FALSE;
164			sc_status = SCError();
165			goto done;
166		}
167
168		bundle = _SC_CFBundleGet();
169		if (bundle != NULL) {
170			setName = CFBundleCopyLocalizedString(bundle,
171							      CFSTR("DEFAULT_SET_NAME"),
172							      CFSTR("Automatic"),
173							      NULL);
174		}
175
176		ok = SCNetworkSetSetName(set, (setName != NULL) ? setName : CFSTR("Automatic"));
177		if (!ok) {
178			sc_status = SCError();
179			goto done;
180		}
181
182		ok = SCNetworkSetSetCurrent(set);
183		if (!ok) {
184			sc_status = SCError();
185			goto done;
186		}
187	}
188
189	ok = SCNetworkSetEstablishDefaultConfiguration(set);
190	if (!ok) {
191		sc_status = SCError();
192		goto done;
193	}
194
195    done :
196
197	if (ok) {
198		ok = SCPreferencesCommitChanges(prefs);
199		if (ok) {
200			SCLog(TRUE, LOG_NOTICE, CFSTR("New network configuration saved"));
201			updated = TRUE;
202		} else {
203			sc_status = SCError();
204			if (sc_status == EROFS) {
205				/* a read-only fileysstem is OK */
206				ok = TRUE;
207
208				/* ... but we don't want to synchronize */
209				rofs = TRUE;
210			}
211		}
212
213		/* apply (committed or temporary/read-only) changes */
214		(void) SCPreferencesApplyChanges(prefs);
215	} else if ((current == NULL) && (set != NULL)) {
216		(void) SCNetworkSetRemove(set);
217	}
218
219	if (!ok) {
220		SCLog(TRUE, LOG_ERR,
221		      CFSTR("Could not establish network configuration: %s"),
222		      SCErrorString(sc_status));
223	}
224
225	(void)SCPreferencesUnlock(prefs);
226	if (setName != NULL) CFRelease(setName);
227	if (set != NULL) CFRelease(set);
228	return updated;
229}
230
231
232static Boolean
233quiet(Boolean *timeout)
234{
235	CFDictionaryRef	dict;
236	Boolean		_quiet		= FALSE;
237	Boolean		_timeout	= FALSE;
238
239	// check if quiet
240	dict = SCDynamicStoreCopyValue(store, initKey);
241	if (dict != NULL) {
242		if (isA_CFDictionary(dict)) {
243			if (CFDictionaryContainsKey(dict, CFSTR("*QUIET*"))) {
244				_quiet = TRUE;
245			}
246			if (CFDictionaryContainsKey(dict, CFSTR("*TIMEOUT*"))) {
247				_timeout = TRUE;
248			}
249		}
250		CFRelease(dict);
251	}
252
253	if (timeout != NULL) {
254		*timeout = _timeout;
255	}
256	return _quiet;
257}
258
259
260static void
261watchQuietDisable()
262{
263	if ((initKey == NULL) || (initRls == NULL)) {
264		return;
265	}
266
267	(void) SCDynamicStoreSetNotificationKeys(store, NULL, NULL);
268
269	CFRunLoopSourceInvalidate(initRls);
270	CFRelease(initRls);
271	initRls = NULL;
272
273	CFRelease(initKey);
274	initKey = NULL;
275
276	return;
277}
278
279
280static void
281watchQuietEnable()
282{
283	CFArrayRef	keys;
284	Boolean		ok;
285
286	initKey = SCDynamicStoreKeyCreate(NULL,
287					  CFSTR("%@" "InterfaceNamer"),
288					  kSCDynamicStoreDomainPlugin);
289
290	initRls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
291	CFRunLoopAddSource(CFRunLoopGetCurrent(), initRls, kCFRunLoopDefaultMode);
292
293	keys = CFArrayCreate(NULL, (const void **)&initKey, 1, &kCFTypeArrayCallBacks);
294	ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL);
295	CFRelease(keys);
296	if (!ok) {
297		SCLog(TRUE, LOG_ERR,
298		      CFSTR("SCDynamicStoreSetNotificationKeys() failed: %s\n"), SCErrorString(SCError()));
299		watchQuietDisable();
300	}
301
302	return;
303}
304
305
306
307
308static void
309watchQuietCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info)
310{
311	Boolean	_quiet;
312	Boolean	_timeout	= FALSE;
313
314	_quiet = quiet(&_timeout);
315	if (_quiet
316#if	!TARGET_OS_IPHONE
317	    || _timeout
318#endif	/* !TARGET_OS_IPHONE */
319	   ) {
320		watchQuietDisable();
321	}
322
323	if (_quiet || _timeout) {
324		static int	logged	= 0;
325
326		(void) establishNewPreferences();
327		if (_timeout && (logged++ == 0)) {
328			SCLog(TRUE, LOG_NOTICE,
329			      CFSTR("Network configuration creation timed out waiting for IORegistry"));
330		}
331	}
332
333	return;
334}
335
336
337static void
338updateCache(const void *key, const void *value, void *context)
339{
340	CFStringRef		configKey	= (CFStringRef)key;
341	CFPropertyListRef	configData	= (CFPropertyListRef)value;
342	CFPropertyListRef	cacheData;
343	CFIndex			i;
344
345	cacheData = CFDictionaryGetValue(currentPrefs, configKey);
346	if (cacheData) {
347		/* key exists */
348		if (CFEqual(cacheData, configData)) {
349			/*
350			 * if the old & new property list values have
351			 * not changed then we don't need to update
352			 * the preference.
353			 */
354			CFArrayAppendValue(unchangedPrefsKeys, configKey);
355		}
356	}
357
358	/* in any case, this key should not be removed */
359	i = CFArrayGetFirstIndexOfValue(removedPrefsKeys,
360					CFRangeMake(0, CFArrayGetCount(removedPrefsKeys)),
361					configKey);
362	if (i != kCFNotFound) {
363		CFArrayRemoveValueAtIndex(removedPrefsKeys, i);
364	}
365
366	return;
367}
368
369
370static void
371flatten(SCPreferencesRef	prefs,
372	CFStringRef		key,
373	CFDictionaryRef		base)
374{
375	CFDictionaryRef		subset;
376	CFStringRef		link;
377	CFMutableDictionaryRef	myDict;
378	CFStringRef		myKey;
379	CFIndex			i;
380	CFIndex			nKeys;
381	const void		**keys;
382	const void		**vals;
383
384	if (!CFDictionaryGetValueIfPresent(base, kSCResvLink, (const void **)&link)) {
385		/* if this dictionary is not linked */
386		subset = base;
387	} else {
388		/* if __LINK__ key is present */
389		subset = SCPreferencesPathGetValue(prefs, link);
390		if (!subset) {
391			/* if error with link */
392			SCLog(TRUE, LOG_ERR,
393			      CFSTR("SCPreferencesPathGetValue(,%@,) failed: %s"),
394			      link,
395			      SCErrorString(SCError()));
396			return;
397		}
398	}
399
400	if (CFDictionaryContainsKey(subset, kSCResvInactive)) {
401		/* if __INACTIVE__ key is present */
402		return;
403	}
404
405	myKey = CFStringCreateWithFormat(NULL,
406					 NULL,
407					 CFSTR("%@%@"),
408					 kSCDynamicStoreDomainSetup,
409					 key);
410
411	myDict = (CFMutableDictionaryRef)CFDictionaryGetValue(newPrefs, myKey);
412	if (myDict) {
413		myDict = CFDictionaryCreateMutableCopy(NULL,
414						       0,
415						       (CFDictionaryRef)myDict);
416	} else {
417		myDict = CFDictionaryCreateMutable(NULL,
418						   0,
419						   &kCFTypeDictionaryKeyCallBacks,
420						   &kCFTypeDictionaryValueCallBacks);
421	}
422
423	nKeys = CFDictionaryGetCount(subset);
424	if (nKeys > 0) {
425		keys  = CFAllocatorAllocate(NULL, nKeys * sizeof(CFStringRef)      , 0);
426		vals  = CFAllocatorAllocate(NULL, nKeys * sizeof(CFPropertyListRef), 0);
427		CFDictionaryGetKeysAndValues(subset, keys, vals);
428		for (i = 0; i < nKeys; i++) {
429			if (CFGetTypeID((CFTypeRef)vals[i]) != CFDictionaryGetTypeID()) {
430				/* add this key/value to the current dictionary */
431				CFDictionarySetValue(myDict, keys[i], vals[i]);
432			} else {
433				CFStringRef	subKey;
434
435				/* flatten [sub]dictionaries */
436				subKey = CFStringCreateWithFormat(NULL,
437								  NULL,
438								  CFSTR("%@%s%@"),
439								  key,
440								  CFEqual(key, CFSTR("/")) ? "" : "/",
441								  keys[i]);
442				flatten(prefs, subKey, vals[i]);
443				CFRelease(subKey);
444			}
445		}
446		CFAllocatorDeallocate(NULL, keys);
447		CFAllocatorDeallocate(NULL, vals);
448	}
449
450	if (CFDictionaryGetCount(myDict) > 0) {
451		/* add this dictionary to the new preferences */
452		CFDictionarySetValue(newPrefs, myKey, myDict);
453	}
454
455	CFRelease(myDict);
456	CFRelease(myKey);
457
458	return;
459}
460
461
462static void
463updateSCDynamicStore(SCPreferencesRef prefs)
464{
465	CFStringRef		current		= NULL;
466	CFDateRef		date		= NULL;
467	CFMutableDictionaryRef	dict		= NULL;
468	CFDictionaryRef		global		= NULL;
469	CFIndex			i;
470	CFArrayRef		keys;
471	CFIndex			n;
472	CFStringRef		pattern;
473	CFMutableArrayRef	patterns;
474	CFDictionaryRef		set		= NULL;
475
476	/*
477	 * initialize old preferences, new preferences, an array
478	 * of keys which have not changed, and an array of keys
479	 * to be removed (cleaned up).
480	 */
481
482	patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
483	pattern  = CFStringCreateWithFormat(NULL,
484					    NULL,
485					    CFSTR("^%@.*"),
486					    kSCDynamicStoreDomainSetup);
487	CFArrayAppendValue(patterns, pattern);
488	dict = (CFMutableDictionaryRef)SCDynamicStoreCopyMultiple(store, NULL, patterns);
489	CFRelease(patterns);
490	CFRelease(pattern);
491	if (dict) {
492		currentPrefs = CFDictionaryCreateMutableCopy(NULL, 0, dict);
493		CFRelease(dict);
494	} else {
495		currentPrefs = CFDictionaryCreateMutable(NULL,
496							 0,
497							 &kCFTypeDictionaryKeyCallBacks,
498							 &kCFTypeDictionaryValueCallBacks);
499	}
500
501	unchangedPrefsKeys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
502
503	i = CFDictionaryGetCount(currentPrefs);
504	if (i > 0) {
505		const void	**currentKeys;
506		CFArrayRef	array;
507
508		currentKeys = CFAllocatorAllocate(NULL, i * sizeof(CFStringRef), 0);
509		CFDictionaryGetKeysAndValues(currentPrefs, currentKeys, NULL);
510		array = CFArrayCreate(NULL, currentKeys, i, &kCFTypeArrayCallBacks);
511		removedPrefsKeys = CFArrayCreateMutableCopy(NULL, 0, array);
512		CFRelease(array);
513		CFAllocatorDeallocate(NULL, currentKeys);
514	} else {
515		removedPrefsKeys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
516	}
517
518	/*
519	 * The "newPrefs" dictionary will contain the new / updated
520	 * configuration which will be written to the configuration cache.
521	 */
522	newPrefs = CFDictionaryCreateMutable(NULL,
523						 0,
524						 &kCFTypeDictionaryKeyCallBacks,
525						 &kCFTypeDictionaryValueCallBacks);
526
527	/*
528	 * create status dictionary associated with current configuration
529	 * information including:
530	 *   - current set "name" to cache
531	 *   - time stamp indicating when the cache preferences were
532	 *     last updated.
533	 */
534	dict = CFDictionaryCreateMutable(NULL,
535					 0,
536					 &kCFTypeDictionaryKeyCallBacks,
537					 &kCFTypeDictionaryValueCallBacks);
538	date = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
539
540	/*
541	 * load preferences
542	 */
543	keys = SCPreferencesCopyKeyList(prefs);
544	if ((keys == NULL) || (CFArrayGetCount(keys) == 0)) {
545		SCLog(TRUE, LOG_NOTICE, CFSTR("updateConfiguration(): no preferences."));
546		goto done;
547	}
548
549	/*
550	 * get "global" system preferences
551	 */
552	global = SCPreferencesGetValue(prefs, kSCPrefSystem);
553	if (!global) {
554		/* if no global preferences are defined */
555		goto getSet;
556	}
557
558	if (!isA_CFDictionary(global)) {
559		SCLog(TRUE, LOG_ERR,
560		      CFSTR("updateConfiguration(): %@ is not a dictionary."),
561		      kSCPrefSystem);
562		goto done;
563	}
564
565	/* flatten property list */
566	flatten(prefs, CFSTR("/"), global);
567
568    getSet :
569
570	/*
571	 * get current set name
572	 */
573	current = SCPreferencesGetValue(prefs, kSCPrefCurrentSet);
574	if (!current) {
575		/* if current set not defined */
576		goto done;
577	}
578
579	if (!isA_CFString(current)) {
580		SCLog(TRUE, LOG_ERR,
581		      CFSTR("updateConfiguration(): %@ is not a string."),
582		      kSCPrefCurrentSet);
583		goto done;
584	}
585
586	/*
587	 * get current set
588	 */
589	set = SCPreferencesPathGetValue(prefs, current);
590	if (!set) {
591		/* if error with path */
592		SCLog(TRUE, LOG_ERR,
593		      CFSTR("%@ value (%@) not valid"),
594		      kSCPrefCurrentSet,
595		      current);
596		goto done;
597	}
598
599	if (!isA_CFDictionary(set)) {
600		SCLog(TRUE, LOG_ERR,
601		      CFSTR("updateConfiguration(): %@ is not a dictionary."),
602		      current);
603		goto done;
604	}
605
606	/* flatten property list */
607	flatten(prefs, CFSTR("/"), set);
608
609	CFDictionarySetValue(dict, kSCDynamicStorePropSetupCurrentSet, current);
610
611    done :
612
613	/* add last updated time stamp */
614	CFDictionarySetValue(dict, kSCDynamicStorePropSetupLastUpdated, date);
615
616	/* add Setup: key */
617	CFDictionarySetValue(newPrefs, kSCDynamicStoreDomainSetup, dict);
618
619	/* compare current and new preferences */
620	CFDictionaryApplyFunction(newPrefs, updateCache, NULL);
621
622	/* remove those keys which have not changed from the update */
623	n = CFArrayGetCount(unchangedPrefsKeys);
624	for (i = 0; i < n; i++) {
625		CFStringRef	key;
626
627		key = CFArrayGetValueAtIndex(unchangedPrefsKeys, i);
628		CFDictionaryRemoveValue(newPrefs, key);
629	}
630
631	/* Update the dynamic store */
632#ifndef MAIN
633	if (!SCDynamicStoreSetMultiple(store, newPrefs, removedPrefsKeys, NULL)) {
634		SCLog(TRUE, LOG_ERR,
635		      CFSTR("SCDynamicStoreSetMultiple() failed: %s"),
636		      SCErrorString(SCError()));
637	}
638#else	// !MAIN
639	SCLog(TRUE, LOG_NOTICE,
640	      CFSTR("SCDynamicStore\nset: %@\nremove: %@\n"),
641	      newPrefs,
642	      removedPrefsKeys);
643#endif	// !MAIN
644
645	CFRelease(currentPrefs);
646	CFRelease(newPrefs);
647	CFRelease(unchangedPrefsKeys);
648	CFRelease(removedPrefsKeys);
649	if (dict)	CFRelease(dict);
650	if (date)	CFRelease(date);
651	if (keys)	CFRelease(keys);
652	return;
653}
654
655
656static void
657updateConfiguration(SCPreferencesRef		prefs,
658		    SCPreferencesNotification   notificationType,
659		    void			*info)
660{
661
662
663#if	!TARGET_OS_IPHONE
664	if ((notificationType & kSCPreferencesNotificationCommit) == kSCPreferencesNotificationCommit) {
665		SCNetworkSetRef	current;
666
667		current = SCNetworkSetCopyCurrent(prefs);
668		if (current != NULL) {
669			/* network configuration available, disable template creation */
670			watchQuietDisable();
671			CFRelease(current);
672		}
673	}
674#endif	/* !TARGET_OS_IPHONE */
675
676	if ((notificationType & kSCPreferencesNotificationApply) != kSCPreferencesNotificationApply) {
677		return;
678	}
679
680	SCLog(_verbose, LOG_DEBUG, CFSTR("updating configuration"));
681
682	/* update SCDynamicStore (Setup:) */
683	updateSCDynamicStore(prefs);
684
685	/* finished with current prefs, wait for changes */
686	if (!rofs) {
687		SCPreferencesSynchronize(prefs);
688	}
689
690	return;
691}
692
693
694__private_extern__
695void
696prime_PreferencesMonitor()
697{
698	SCLog(_verbose, LOG_DEBUG, CFSTR("prime() called"));
699
700	/* load the initial configuration from the database */
701	updateConfiguration(prefs, kSCPreferencesNotificationApply, (void *)store);
702
703	return;
704}
705
706
707__private_extern__
708void
709load_PreferencesMonitor(CFBundleRef bundle, Boolean bundleVerbose)
710{
711	Boolean	initPrefs	= TRUE;
712
713	if (bundleVerbose) {
714		_verbose = TRUE;
715	}
716
717	SCLog(_verbose, LOG_DEBUG, CFSTR("load() called"));
718	SCLog(_verbose, LOG_DEBUG, CFSTR("  bundle ID = %@"), CFBundleGetIdentifier(bundle));
719
720	/* open a SCDynamicStore session to allow cache updates */
721	store = SCDynamicStoreCreate(NULL,
722				     CFSTR("PreferencesMonitor.bundle"),
723				     watchQuietCallback,
724				     NULL);
725	if (store == NULL) {
726		SCLog(TRUE, LOG_ERR,
727		      CFSTR("SCDynamicStoreCreate() failed: %s"),
728		      SCErrorString(SCError()));
729		goto error;
730	}
731
732	/* open a SCPreferences session */
733#ifndef	MAIN
734	prefs = SCPreferencesCreate(NULL, CFSTR("PreferencesMonitor.bundle"), NULL);
735#else	// !MAIN
736	prefs = SCPreferencesCreate(NULL, CFSTR("PreferencesMonitor.bundle"), CFSTR("/tmp/preferences.plist"));
737#endif	// !MAIN
738	if (prefs != NULL) {
739		Boolean		need_update = FALSE;
740		CFStringRef	new_model;
741
742		new_model = _SC_hw_model();
743
744		/* Need to regenerate the new configuration for new model */
745		if (new_model != NULL) {
746			CFStringRef	old_model;
747
748			old_model = SCPreferencesGetValue(prefs, MODEL);
749			if (old_model != NULL && !_SC_CFEqual(old_model, new_model)) {
750				// if new hardware
751				need_update = TRUE;
752			}
753		}
754
755		if (need_update == FALSE) {
756			SCNetworkSetRef current;
757
758			current = SCNetworkSetCopyCurrent(prefs);
759			if (current != NULL) {
760				/* network configuration available, disable template creation */
761				initPrefs = FALSE;
762				CFRelease(current);
763			}
764		}
765	} else {
766		SCLog(TRUE, LOG_ERR,
767		      CFSTR("SCPreferencesCreate() failed: %s"),
768		      SCErrorString(SCError()));
769		goto error;
770	}
771
772	/*
773	 * register for change notifications.
774	 */
775	if (!SCPreferencesSetCallback(prefs, updateConfiguration, NULL)) {
776		SCLog(TRUE, LOG_ERR,
777		      CFSTR("SCPreferencesSetCallBack() failed: %s"),
778		      SCErrorString(SCError()));
779		goto error;
780	}
781
782	if (!SCPreferencesScheduleWithRunLoop(prefs, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) {
783		SCLog(TRUE, LOG_ERR,
784		      CFSTR("SCPreferencesScheduleWithRunLoop() failed: %s"),
785		      SCErrorString(SCError()));
786		goto error;
787	}
788
789	/*
790	 * if no preferences, initialize with a template (now or
791	 * when IOKit has quiesced).
792	 */
793	if (initPrefs) {
794		watchQuietEnable();
795		watchQuietCallback(store, NULL, NULL);
796	}
797
798	return;
799
800    error :
801
802	watchQuietDisable();
803	if (store != NULL)	CFRelease(store);
804	if (prefs != NULL)	CFRelease(prefs);
805
806	return;
807}
808
809
810#ifdef  MAIN
811int
812main(int argc, char **argv)
813{
814	_sc_log     = FALSE;
815	_sc_verbose = (argc > 1) ? TRUE : FALSE;
816
817	load_PreferencesMonitor(CFBundleGetMainBundle(), (argc > 1) ? TRUE : FALSE);
818	prime_PreferencesMonitor();
819	CFRunLoopRun();
820	/* not reached */
821	exit(0);
822	return 0;
823}
824#endif
825