]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCPOpen.c
2c45b5783ba83ae81dc3459b79c60b8e2f0e3e1c
[apple/configd.git] / SystemConfiguration.fproj / SCPOpen.c
1 /*
2 * Copyright(c) 2000-2004 Apple Computer, 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 * February 16, 2004 Allan Nathanson <ajn@apple.com>
28 * - add preference notification APIs
29 *
30 * June 1, 2001 Allan Nathanson <ajn@apple.com>
31 * - public API conversion
32 *
33 * November 9, 2000 Allan Nathanson <ajn@apple.com>
34 * - initial revision
35 */
36
37 #include <SystemConfiguration/SystemConfiguration.h>
38 #include <SystemConfiguration/SCValidation.h>
39 #include <SystemConfiguration/SCPrivate.h>
40 #include "SCPreferencesInternal.h"
41
42 #include <fcntl.h>
43 #include <pthread.h>
44 #include <unistd.h>
45 #include <sys/errno.h>
46
47
48 static CFStringRef
49 __SCPreferencesCopyDescription(CFTypeRef cf) {
50 CFAllocatorRef allocator = CFGetAllocator(cf);
51 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)cf;
52 CFMutableStringRef result;
53
54 result = CFStringCreateMutable(allocator, 0);
55 CFStringAppendFormat(result, NULL, CFSTR("<SCPreferences %p [%p]> {"), cf, allocator);
56 CFStringAppendFormat(result, NULL, CFSTR("name = %@"), prefsPrivate->name);
57 CFStringAppendFormat(result, NULL, CFSTR(", id = %@"), prefsPrivate->prefsID);
58 if (prefsPrivate->perUser) {
59 CFStringAppendFormat(result, NULL, CFSTR(" (for user %@)"), prefsPrivate->user);
60 }
61 CFStringAppendFormat(result, NULL, CFSTR(", path = %s"),
62 prefsPrivate->newPath ? prefsPrivate->newPath : prefsPrivate->path);
63 if (prefsPrivate->accessed) {
64 CFStringAppendFormat(result, NULL, CFSTR(", accessed"));
65 }
66 if (prefsPrivate->changed) {
67 CFStringAppendFormat(result, NULL, CFSTR(", changed"));
68 }
69 if (prefsPrivate->locked) {
70 CFStringAppendFormat(result, NULL, CFSTR(", locked"));
71 }
72 CFStringAppendFormat(result, NULL, CFSTR("}"));
73
74 return result;
75 }
76
77
78 static void
79 __SCPreferencesDeallocate(CFTypeRef cf)
80 {
81 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)cf;
82
83 /* release resources */
84
85 pthread_mutex_destroy(&prefsPrivate->lock);
86
87 if (prefsPrivate->name) CFRelease(prefsPrivate->name);
88 if (prefsPrivate->prefsID) CFRelease(prefsPrivate->prefsID);
89 if (prefsPrivate->user) CFRelease(prefsPrivate->user);
90 if (prefsPrivate->path) CFAllocatorDeallocate(NULL, prefsPrivate->path);
91 if (prefsPrivate->newPath) CFAllocatorDeallocate(NULL, prefsPrivate->newPath);
92 if (prefsPrivate->signature) CFRelease(prefsPrivate->signature);
93 if (prefsPrivate->session) CFRelease(prefsPrivate->session);
94 if (prefsPrivate->sessionKeyLock) CFRelease(prefsPrivate->sessionKeyLock);
95 if (prefsPrivate->sessionKeyCommit) CFRelease(prefsPrivate->sessionKeyCommit);
96 if (prefsPrivate->sessionKeyApply) CFRelease(prefsPrivate->sessionKeyApply);
97 if (prefsPrivate->rlsContext.release != NULL) {
98 (*prefsPrivate->rlsContext.release)(prefsPrivate->rlsContext.info);
99 }
100 if (prefsPrivate->prefs) CFRelease(prefsPrivate->prefs);
101
102 return;
103 }
104
105
106 static CFTypeID __kSCPreferencesTypeID = _kCFRuntimeNotATypeID;
107
108
109 static const CFRuntimeClass __SCPreferencesClass = {
110 0, // version
111 "SCPreferences", // className
112 NULL, // init
113 NULL, // copy
114 __SCPreferencesDeallocate, // dealloc
115 NULL, // equal
116 NULL, // hash
117 NULL, // copyFormattingDesc
118 __SCPreferencesCopyDescription // copyDebugDesc
119 };
120
121
122 static pthread_once_t initialized = PTHREAD_ONCE_INIT;
123
124 static void
125 __SCPreferencesInitialize(void) {
126 __kSCPreferencesTypeID = _CFRuntimeRegisterClass(&__SCPreferencesClass);
127 return;
128 }
129
130
131 static SCPreferencesPrivateRef
132 __SCPreferencesCreatePrivate(CFAllocatorRef allocator)
133 {
134 SCPreferencesPrivateRef prefsPrivate;
135 uint32_t size;
136
137 /* initialize runtime */
138 pthread_once(&initialized, __SCPreferencesInitialize);
139
140 /* allocate prefs session */
141 size = sizeof(SCPreferencesPrivate) - sizeof(CFRuntimeBase);
142 prefsPrivate = (SCPreferencesPrivateRef)_CFRuntimeCreateInstance(allocator,
143 __kSCPreferencesTypeID,
144 size,
145 NULL);
146 if (prefsPrivate == NULL) {
147 return NULL;
148 }
149
150 pthread_mutex_init(&prefsPrivate->lock, NULL);
151
152 prefsPrivate->name = NULL;
153 prefsPrivate->prefsID = NULL;
154 prefsPrivate->perUser = FALSE;
155 prefsPrivate->user = NULL;
156 prefsPrivate->path = NULL;
157 prefsPrivate->newPath = NULL; // new prefs path
158 prefsPrivate->signature = NULL;
159 prefsPrivate->session = NULL;
160 prefsPrivate->sessionKeyLock = NULL;
161 prefsPrivate->sessionKeyCommit = NULL;
162 prefsPrivate->sessionKeyApply = NULL;
163 prefsPrivate->rls = NULL;
164 prefsPrivate->rlsFunction = NULL;
165 prefsPrivate->rlsContext.info = NULL;
166 prefsPrivate->rlsContext.retain = NULL;
167 prefsPrivate->rlsContext.release = NULL;
168 prefsPrivate->rlsContext.copyDescription = NULL;
169 prefsPrivate->rlList = NULL;
170 prefsPrivate->prefs = NULL;
171 prefsPrivate->accessed = FALSE;
172 prefsPrivate->changed = FALSE;
173 prefsPrivate->locked = FALSE;
174 prefsPrivate->isRoot = (geteuid() == 0);
175
176 return prefsPrivate;
177 }
178
179
180 __private_extern__ SCPreferencesRef
181 __SCPreferencesCreate(CFAllocatorRef allocator,
182 CFStringRef name,
183 CFStringRef prefsID,
184 Boolean perUser,
185 CFStringRef user)
186 {
187 int fd = -1;
188 SCPreferencesPrivateRef prefsPrivate;
189 int sc_status = kSCStatusOK;
190
191 /*
192 * allocate and initialize a new prefs session
193 */
194 prefsPrivate = __SCPreferencesCreatePrivate(allocator);
195 if (prefsPrivate == NULL) {
196 return NULL;
197 }
198
199 retry :
200
201 /*
202 * convert prefsID to path
203 */
204 prefsPrivate->path = __SCPreferencesPath(allocator,
205 prefsID,
206 perUser,
207 user,
208 (prefsPrivate->newPath == NULL));
209 if (prefsPrivate->path == NULL) {
210 sc_status = kSCStatusFailed;
211 goto error;
212 }
213
214 /*
215 * open file
216 */
217 fd = open(prefsPrivate->path, O_RDONLY, 0644);
218 if (fd != -1) {
219 (void) close(fd);
220 } else {
221 switch (errno) {
222 case ENOENT :
223 /* no prefs file */
224 if (!perUser &&
225 ((prefsID == NULL) || !CFStringHasPrefix(prefsID, CFSTR("/")))) {
226 /* if default preference ID or relative path */
227 if (prefsPrivate->newPath == NULL) {
228 /*
229 * we've looked in the "new" prefs directory
230 * without success. Save the "new" path and
231 * look in the "old" prefs directory.
232 */
233 prefsPrivate->newPath = prefsPrivate->path;
234 goto retry;
235 } else {
236 /*
237 * we've looked in both the "new" and "old"
238 * prefs directories without success. USe
239 * the "new" path.
240 */
241 CFAllocatorDeallocate(NULL, prefsPrivate->path);
242 prefsPrivate->path = prefsPrivate->newPath;
243 prefsPrivate->newPath = NULL;
244 }
245 }
246
247 /* no preference data, start fresh */
248 goto done;
249 case EACCES :
250 sc_status = kSCStatusAccessError;
251 break;
252 default :
253 sc_status = kSCStatusFailed;
254 break;
255 }
256 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("__SCPreferencesCreate open() failed: %s"), strerror(errno));
257 goto error;
258 }
259
260 done :
261
262 /*
263 * all OK
264 */
265 prefsPrivate->name = CFStringCreateCopy(allocator, name);
266 if (prefsID != NULL) prefsPrivate->prefsID = CFStringCreateCopy(allocator, prefsID);
267 prefsPrivate->perUser = perUser;
268 if (user != NULL) prefsPrivate->user = CFStringCreateCopy(allocator, user);
269 return (SCPreferencesRef)prefsPrivate;
270
271 error :
272
273 if (fd != -1) (void) close(fd);
274 CFRelease(prefsPrivate);
275 _SCErrorSet(sc_status);
276 return NULL;
277 }
278
279
280 __private_extern__ Boolean
281 __SCPreferencesAccess(SCPreferencesRef prefs)
282 {
283 CFAllocatorRef allocator = CFGetAllocator(prefs);
284 int fd = -1;
285 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
286 int sc_status = kSCStatusOK;
287 struct stat statBuf;
288
289 if (prefsPrivate->accessed) {
290 // if preference data has already been accessed
291 return TRUE;
292 }
293
294 fd = open(prefsPrivate->path, O_RDONLY, 0644);
295 if (fd != -1) {
296 // create signature
297 if (fstat(fd, &statBuf) == -1) {
298 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("__SCPreferencesAccess fstat() failed: %s"), strerror(errno));
299 sc_status = kSCStatusFailed;
300 goto error;
301 }
302 } else {
303 switch (errno) {
304 case ENOENT :
305 /* no preference data, start fresh */
306 bzero(&statBuf, sizeof(statBuf));
307 goto create_1;
308 case EACCES :
309 sc_status = kSCStatusAccessError;
310 break;
311 default :
312 sc_status = kSCStatusFailed;
313 break;
314 }
315 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("__SCPreferencesAccess open() failed: %s"), strerror(errno));
316 goto error;
317 }
318
319 create_1 :
320
321 if (prefsPrivate->signature != NULL) CFRelease(prefsPrivate->signature);
322 prefsPrivate->signature = __SCPSignatureFromStatbuf(&statBuf);
323
324 if (statBuf.st_size > 0) {
325 CFDictionaryRef dict;
326 CFMutableDataRef xmlData;
327 CFStringRef xmlError;
328
329 /*
330 * extract property list
331 */
332 xmlData = CFDataCreateMutable(allocator, statBuf.st_size);
333 CFDataSetLength(xmlData, statBuf.st_size);
334 if (read(fd, (void *)CFDataGetBytePtr(xmlData), statBuf.st_size) != statBuf.st_size) {
335 /* corrupt prefs file, start fresh */
336 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("__SCPreferencesAccess read(): could not load preference data."));
337 CFRelease(xmlData);
338 xmlData = NULL;
339 goto create_2;
340 }
341
342 /*
343 * load preferences
344 */
345 dict = CFPropertyListCreateFromXMLData(allocator,
346 xmlData,
347 kCFPropertyListImmutable,
348 &xmlError);
349 CFRelease(xmlData);
350 if (dict == NULL) {
351 /* corrupt prefs file, start fresh */
352 if (xmlError != NULL) {
353 SCLog(TRUE, LOG_ERR,
354 CFSTR("__SCPreferencesAccess CFPropertyListCreateFromXMLData(): %@"),
355 xmlError);
356 CFRelease(xmlError);
357 }
358 goto create_2;
359 }
360
361 /*
362 * make sure that we've got a dictionary
363 */
364 if (!isA_CFDictionary(dict)) {
365 /* corrupt prefs file, start fresh */
366 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("__SCPreferencesAccess CFGetTypeID(): not a dictionary."));
367 CFRelease(dict);
368 goto create_2;
369 }
370
371 prefsPrivate->prefs = CFDictionaryCreateMutableCopy(allocator, 0, dict);
372 CFRelease(dict);
373 }
374
375 create_2 :
376
377 if (fd != -1) {
378 (void) close(fd);
379 fd = -1;
380 }
381
382 if (prefsPrivate->prefs == NULL) {
383 /*
384 * new file, create empty preferences
385 */
386 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("__SCPreferencesAccess(): creating new dictionary."));
387 prefsPrivate->prefs = CFDictionaryCreateMutable(allocator,
388 0,
389 &kCFTypeDictionaryKeyCallBacks,
390 &kCFTypeDictionaryValueCallBacks);
391 prefsPrivate->changed = TRUE;
392 }
393
394 prefsPrivate->accessed = TRUE;
395 return TRUE;
396
397 error :
398
399 if (fd != -1) (void) close(fd);
400 _SCErrorSet(sc_status);
401 return FALSE;
402
403 }
404
405
406 SCPreferencesRef
407 SCPreferencesCreate(CFAllocatorRef allocator,
408 CFStringRef name,
409 CFStringRef prefsID)
410 {
411 return __SCPreferencesCreate(allocator, name, prefsID, FALSE, NULL);
412 }
413
414
415 SCPreferencesRef
416 SCUserPreferencesCreate(CFAllocatorRef allocator,
417 CFStringRef name,
418 CFStringRef prefsID,
419 CFStringRef user)
420 {
421 return __SCPreferencesCreate(allocator, name, prefsID, TRUE, user);
422 }
423
424
425 CFTypeID
426 SCPreferencesGetTypeID(void) {
427 pthread_once(&initialized, __SCPreferencesInitialize); /* initialize runtime */
428 return __kSCPreferencesTypeID;
429 }
430
431
432 static void
433 prefsNotify(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info)
434 {
435 void *context_info;
436 void (*context_release)(const void *);
437 CFIndex i;
438 CFIndex n;
439 SCPreferencesNotification notify = 0;
440 SCPreferencesRef prefs = (SCPreferencesRef)info;
441 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
442 SCPreferencesCallBack rlsFunction;
443
444 n = (changedKeys != NULL) ? CFArrayGetCount(changedKeys) : 0;
445 for (i = 0; i < n; i++) {
446 CFStringRef key;
447
448 key = CFArrayGetValueAtIndex(changedKeys, i);
449 if (CFEqual(key, prefsPrivate->sessionKeyCommit)) {
450 // if preferences have been saved
451 notify |= kSCPreferencesNotificationCommit;
452 }
453 if (CFEqual(key, prefsPrivate->sessionKeyApply)) {
454 // if stored preferences should be applied to current configuration
455 notify |= kSCPreferencesNotificationApply;
456 }
457 }
458
459 if (notify == 0) {
460 // if no changes
461 return;
462 }
463
464 pthread_mutex_lock(&prefsPrivate->lock);
465
466 /* callout */
467 rlsFunction = prefsPrivate->rlsFunction;
468 if (prefsPrivate->rlsContext.retain != NULL) {
469 context_info = (void *)prefsPrivate->rlsContext.retain(prefsPrivate->rlsContext.info);
470 context_release = prefsPrivate->rlsContext.release;
471 } else {
472 context_info = prefsPrivate->rlsContext.info;
473 context_release = NULL;
474 }
475
476 pthread_mutex_unlock(&prefsPrivate->lock);
477
478 if (rlsFunction != NULL) {
479 (*rlsFunction)(prefs, notify, context_info);
480 }
481
482 if (context_release != NULL) {
483 (*context_release)(context_info);
484 }
485
486 return;
487 }
488
489
490 __private_extern__ Boolean
491 __SCPreferencesAddSession(SCPreferencesRef prefs)
492 {
493 CFAllocatorRef allocator = CFGetAllocator(prefs);
494 SCDynamicStoreContext context = { 0
495 , (void *)prefs
496 , NULL
497 , NULL
498 , NULL
499 };
500 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
501
502 /* establish a dynamic store session */
503 prefsPrivate->session = SCDynamicStoreCreate(allocator,
504 CFSTR("SCPreferences"),
505 prefsNotify,
506 &context);
507 if (prefsPrivate->session == NULL) {
508 SCLog(_sc_verbose, LOG_INFO, CFSTR("__SCPreferencesAddSession SCDynamicStoreCreate() failed"));
509 return FALSE;
510 }
511
512 /* create the session "commit" key */
513 prefsPrivate->sessionKeyCommit = _SCPNotificationKey(NULL,
514 prefsPrivate->prefsID,
515 prefsPrivate->perUser,
516 prefsPrivate->user,
517 kSCPreferencesKeyCommit);
518
519 /* create the session "apply" key */
520 prefsPrivate->sessionKeyApply = _SCPNotificationKey(NULL,
521 prefsPrivate->prefsID,
522 prefsPrivate->perUser,
523 prefsPrivate->user,
524 kSCPreferencesKeyApply);
525
526 return TRUE;
527 }
528
529
530 Boolean
531 SCPreferencesSetCallback(SCPreferencesRef prefs,
532 SCPreferencesCallBack callout,
533 SCPreferencesContext *context)
534 {
535 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
536
537 if (prefs == NULL) {
538 /* sorry, you must provide a session */
539 _SCErrorSet(kSCStatusNoPrefsSession);
540 return FALSE;
541 }
542
543 pthread_mutex_lock(&prefsPrivate->lock);
544
545 if (prefsPrivate->rlsContext.release != NULL) {
546 /* let go of the current context */
547 (*prefsPrivate->rlsContext.release)(prefsPrivate->rlsContext.info);
548 }
549
550 prefsPrivate->rlsFunction = callout;
551 prefsPrivate->rlsContext.info = NULL;
552 prefsPrivate->rlsContext.retain = NULL;
553 prefsPrivate->rlsContext.release = NULL;
554 prefsPrivate->rlsContext.copyDescription = NULL;
555 if (context != NULL) {
556 bcopy(context, &prefsPrivate->rlsContext, sizeof(SCPreferencesContext));
557 if (context->retain != NULL) {
558 prefsPrivate->rlsContext.info = (void *)(*context->retain)(context->info);
559 }
560 }
561
562 pthread_mutex_unlock(&prefsPrivate->lock);
563
564 return TRUE;
565 }
566
567
568 Boolean
569 SCPreferencesScheduleWithRunLoop(SCPreferencesRef prefs,
570 CFRunLoopRef runLoop,
571 CFStringRef runLoopMode)
572 {
573 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
574
575 if (prefs == NULL) {
576 /* sorry, you must provide a session */
577 _SCErrorSet(kSCStatusNoPrefsSession);
578 return FALSE;
579 }
580
581 pthread_mutex_lock(&prefsPrivate->lock);
582
583 if (prefsPrivate->rls == NULL) {
584 CFMutableArrayRef keys;
585
586 if (prefsPrivate->session == NULL) {
587 __SCPreferencesAddSession(prefs);
588 }
589
590 CFRetain(prefs); // hold a reference to the prefs
591
592 keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
593 CFArrayAppendValue(keys, prefsPrivate->sessionKeyCommit);
594 CFArrayAppendValue(keys, prefsPrivate->sessionKeyApply);
595 (void)SCDynamicStoreSetNotificationKeys(prefsPrivate->session, keys, NULL);
596 CFRelease(keys);
597
598 prefsPrivate->rls = SCDynamicStoreCreateRunLoopSource(NULL, prefsPrivate->session, 0);
599 prefsPrivate->rlList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
600 }
601
602 if (!_SC_isScheduled(NULL, runLoop, runLoopMode, prefsPrivate->rlList)) {
603 /*
604 * if we do not already have notifications scheduled with
605 * this runLoop / runLoopMode
606 */
607 CFRunLoopAddSource(runLoop, prefsPrivate->rls, runLoopMode);
608 }
609
610 _SC_schedule(prefs, runLoop, runLoopMode, prefsPrivate->rlList);
611
612 pthread_mutex_unlock(&prefsPrivate->lock);
613 return TRUE;
614 }
615
616
617 Boolean
618 SCPreferencesUnscheduleFromRunLoop(SCPreferencesRef prefs,
619 CFRunLoopRef runLoop,
620 CFStringRef runLoopMode)
621 {
622 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
623 CFIndex n;
624 Boolean ok = FALSE;
625
626 if (prefs == NULL) {
627 /* sorry, you must provide a session */
628 _SCErrorSet(kSCStatusNoPrefsSession);
629 return FALSE;
630 }
631
632 pthread_mutex_lock(&prefsPrivate->lock);
633
634 if (prefsPrivate->rls == NULL) {
635 /* if not currently scheduled */
636 goto done;
637 }
638
639 if (!_SC_unschedule(NULL, runLoop, runLoopMode, prefsPrivate->rlList, FALSE)) {
640 /* if not currently scheduled */
641 goto done;
642 }
643
644 n = CFArrayGetCount(prefsPrivate->rlList);
645 if (n == 0 || !_SC_isScheduled(NULL, runLoop, runLoopMode, prefsPrivate->rlList)) {
646 /*
647 * if we are no longer scheduled to receive notifications for
648 * this runLoop / runLoopMode
649 */
650 CFRunLoopRemoveSource(runLoop, prefsPrivate->rls, runLoopMode);
651
652 if (n == 0) {
653 CFArrayRef changedKeys;
654
655 /*
656 * if *all* notifications have been unscheduled
657 */
658 CFRunLoopSourceInvalidate(prefsPrivate->rls);
659 CFRelease(prefsPrivate->rls);
660 prefsPrivate->rls = NULL;
661 CFRelease(prefsPrivate->rlList);
662 prefsPrivate->rlList = NULL;
663
664 CFRelease(prefs); // release our reference to the prefs
665
666 // no need to track changes
667 (void)SCDynamicStoreSetNotificationKeys(prefsPrivate->session, NULL, NULL);
668
669 // clear out any pending notifications
670 changedKeys = SCDynamicStoreCopyNotifiedKeys(prefsPrivate->session);
671 if (changedKeys != NULL) {
672 CFRelease(changedKeys);
673 }
674 }
675 }
676
677 ok = TRUE;
678
679 done :
680
681 pthread_mutex_unlock(&prefsPrivate->lock);
682 return ok;
683 }
684
685
686 void
687 SCPreferencesSynchronize(SCPreferencesRef prefs)
688 {
689 SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
690
691 if (prefs == NULL) {
692 /* sorry, you must provide a session */
693 _SCErrorSet(kSCStatusNoPrefsSession);
694 return;
695 }
696
697 if (prefsPrivate->prefs != NULL) {
698 CFRelease(prefsPrivate->prefs);
699 prefsPrivate->prefs = NULL;
700 }
701 if (prefsPrivate->signature != NULL) {
702 CFRelease(prefsPrivate->signature);
703 prefsPrivate->signature = NULL;
704 }
705 prefsPrivate->accessed = FALSE;
706 prefsPrivate->changed = FALSE;
707 return;
708 }