2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * June 1, 2001 Allan Nathanson <ajn@apple.com>
28 * - public API conversion
30 * March 24, 2000 Allan Nathanson <ajn@apple.com>
39 static __inline__
void
40 my_CFSetApplyFunction(CFSetRef theSet
,
41 CFSetApplierFunction applier
,
44 CFAllocatorRef myAllocator
;
47 myAllocator
= CFGetAllocator(theSet
);
48 mySet
= CFSetCreateCopy(myAllocator
, theSet
);
49 CFSetApplyFunction(mySet
, applier
, context
);
57 __SCDynamicStoreAddWatchedKey(SCDynamicStoreRef store
, CFStringRef key
, Boolean isRegex
, Boolean internal
)
59 int sc_status
= kSCStatusOK
;
60 CFNumberRef sessionNum
= NULL
;
61 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
63 if (_configd_verbose
) {
64 SCLog(TRUE
, LOG_DEBUG
, CFSTR("__SCDynamicStoreAddWatchedKey:"));
65 SCLog(TRUE
, LOG_DEBUG
, CFSTR(" key = %@"), key
);
66 SCLog(TRUE
, LOG_DEBUG
, CFSTR(" isRegex = %s"), isRegex
? "TRUE" : "FALSE");
69 if (!store
|| (storePrivate
->server
== MACH_PORT_NULL
)) {
70 return kSCStatusNoStoreSession
; /* you must have an open session to play */
74 SCTrace(TRUE
, _configd_trace
,
75 CFSTR("%s : %5d : %s : %@\n"),
76 internal
? "*watch+" : "watch+ ",
78 isRegex
? "pattern" : "key",
82 sessionNum
= CFNumberCreate(NULL
, kCFNumberIntType
, &storePrivate
->server
);
85 if (CFSetContainsValue(storePrivate
->patterns
, key
)) {
86 /* sorry, pattern already exists in notifier list */
87 sc_status
= kSCStatusKeyExists
;
92 * add this session as a pattern watcher
94 if (!patternAddSession(key
, sessionNum
)) {
95 sc_status
= kSCStatusInvalidArgument
;
99 /* add pattern to this sessions notifier list */
100 CFSetAddValue(storePrivate
->patterns
, key
);
102 if (CFSetContainsValue(storePrivate
->keys
, key
)) {
103 /* sorry, key already exists in notifier list */
104 sc_status
= kSCStatusKeyExists
;
109 * We are watching a specific key. As such, update the
110 * store to mark our interest in any changes.
112 _addWatcher(sessionNum
, key
);
114 /* add key to this sessions notifier list */
115 CFSetAddValue(storePrivate
->keys
, key
);
120 if (sessionNum
) CFRelease(sessionNum
);
127 _notifyadd(mach_port_t server
,
128 xmlData_t keyRef
, /* raw XML bytes */
129 mach_msg_type_number_t keyLen
,
134 serverSessionRef mySession
= getSession(server
);
135 CFStringRef key
; /* key (un-serialized) */
137 if (_configd_verbose
) {
138 SCLog(TRUE
, LOG_DEBUG
, CFSTR("Add notification key for this session."));
139 SCLog(TRUE
, LOG_DEBUG
, CFSTR(" server = %d"), server
);
142 /* un-serialize the key */
143 if (!_SCUnserializeString(&key
, NULL
, (void *)keyRef
, keyLen
)) {
144 *sc_status
= kSCStatusFailed
;
148 if (!isA_CFString(key
)) {
149 *sc_status
= kSCStatusInvalidArgument
;
155 *sc_status
= kSCStatusNoStoreSession
; /* you must have an open session to play */
160 *sc_status
= __SCDynamicStoreAddWatchedKey(mySession
->store
, key
, isRegex
!= 0, FALSE
);
168 * "context" argument for removeOldKey() and addNewKey()
171 SCDynamicStoreRef store
;
172 CFSetRef oldKeys
; /* for addNewKey */
173 CFArrayRef newKeys
; /* for removeOldKey */
176 } updateKeysContext
, *updateKeysContextRef
;
180 removeOldKey(const void *value
, void *context
)
182 CFStringRef oldKey
= (CFStringRef
)value
;
183 updateKeysContextRef myContextRef
= (updateKeysContextRef
)context
;
185 if (myContextRef
->sc_status
!= kSCStatusOK
) {
189 if (!myContextRef
->newKeys
||
190 !CFArrayContainsValue(myContextRef
->newKeys
,
191 CFRangeMake(0, CFArrayGetCount(myContextRef
->newKeys
)),
193 /* the old notification key is not being retained, remove it */
194 myContextRef
->sc_status
= __SCDynamicStoreRemoveWatchedKey(myContextRef
->store
,
196 myContextRef
->isRegex
,
205 addNewKey(const void *value
, void *context
)
207 CFStringRef newKey
= (CFStringRef
)value
;
208 updateKeysContextRef myContextRef
= (updateKeysContextRef
)context
;
210 if (myContextRef
->sc_status
!= kSCStatusOK
) {
214 if (!myContextRef
->oldKeys
||
215 !CFSetContainsValue(myContextRef
->oldKeys
, newKey
)) {
216 /* if this is a new notification key */
217 myContextRef
->sc_status
= __SCDynamicStoreAddWatchedKey(myContextRef
->store
,
219 myContextRef
->isRegex
,
229 __SCDynamicStoreSetNotificationKeys(SCDynamicStoreRef store
, CFArrayRef keys
, CFArrayRef patterns
)
231 updateKeysContext myContext
;
232 SCDynamicStorePrivateRef storePrivate
= (SCDynamicStorePrivateRef
)store
;
234 if (_configd_verbose
) {
235 SCLog(TRUE
, LOG_DEBUG
, CFSTR("__SCDynamicStoreSetNotificationKeys:"));
236 SCLog(TRUE
, LOG_DEBUG
, CFSTR(" keys = %@"), keys
);
237 SCLog(TRUE
, LOG_DEBUG
, CFSTR(" patterns = %@"), patterns
);
240 if (!store
|| (storePrivate
->server
== MACH_PORT_NULL
)) {
241 return kSCStatusNoStoreSession
; /* you must have an open session to play */
244 if (_configd_trace
) {
245 SCTrace(TRUE
, _configd_trace
,
246 CFSTR("watch : %5d : %d keys, %d patterns\n"),
247 storePrivate
->server
,
248 keys
? CFArrayGetCount(keys
) : 0,
249 patterns
? CFArrayGetCount(patterns
) : 0);
252 myContext
.store
= store
;
253 myContext
.sc_status
= kSCStatusOK
;
255 /* remove any previously registered keys, register any new keys */
256 myContext
.oldKeys
= CFSetCreateCopy(NULL
, storePrivate
->keys
);
257 myContext
.newKeys
= keys
;
258 myContext
.isRegex
= FALSE
;
259 my_CFSetApplyFunction(storePrivate
->keys
, removeOldKey
, &myContext
);
261 CFArrayApplyFunction(keys
,
262 CFRangeMake(0, CFArrayGetCount(keys
)),
266 CFRelease(myContext
.oldKeys
);
268 /* remove any previously registered patterns, register any new patterns */
269 myContext
.oldKeys
= CFSetCreateCopy(NULL
, storePrivate
->patterns
);
270 myContext
.newKeys
= patterns
;
271 myContext
.isRegex
= TRUE
;
272 my_CFSetApplyFunction(storePrivate
->patterns
, removeOldKey
, &myContext
);
274 CFArrayApplyFunction(patterns
,
275 CFRangeMake(0, CFArrayGetCount(patterns
)),
279 CFRelease(myContext
.oldKeys
);
281 return myContext
.sc_status
;
287 _notifyset(mach_port_t server
,
288 xmlData_t keysRef
, /* raw XML bytes */
289 mach_msg_type_number_t keysLen
,
290 xmlData_t patternsRef
, /* raw XML bytes */
291 mach_msg_type_number_t patternsLen
,
295 serverSessionRef mySession
= getSession(server
);
296 CFArrayRef keys
= NULL
; /* key (un-serialized) */
297 CFArrayRef patterns
= NULL
; /* patterns (un-serialized) */
299 if (_configd_verbose
) {
300 SCLog(TRUE
, LOG_DEBUG
, CFSTR("Add notification key for this session."));
301 SCLog(TRUE
, LOG_DEBUG
, CFSTR(" server = %d"), server
);
304 *sc_status
= kSCStatusOK
;
306 if (keysRef
&& (keysLen
> 0)) {
307 /* un-serialize the keys */
308 if (!_SCUnserialize((CFPropertyListRef
*)&keys
, NULL
, (void *)keysRef
, keysLen
)) {
309 *sc_status
= kSCStatusFailed
;
310 } else if (!isA_CFArray(keys
)) {
311 *sc_status
= kSCStatusInvalidArgument
;
315 if (patternsRef
&& (patternsLen
> 0)) {
316 /* un-serialize the patterns */
317 if (!_SCUnserialize((CFPropertyListRef
*)&patterns
, NULL
, (void *)patternsRef
, patternsLen
)) {
318 *sc_status
= kSCStatusFailed
;
319 } else if (!isA_CFArray(patterns
)) {
320 *sc_status
= kSCStatusInvalidArgument
;
325 /* you must have an open session to play */
326 *sc_status
= kSCStatusNoStoreSession
;
329 if (*sc_status
== kSCStatusOK
) {
330 *sc_status
= __SCDynamicStoreSetNotificationKeys(mySession
->store
, keys
, patterns
);
333 if (keys
) CFRelease(keys
);
334 if (patterns
) CFRelease(patterns
);