]>
Commit | Line | Data |
---|---|---|
5958d7c0 | 1 | /* |
a5f60add | 2 | * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. |
5958d7c0 A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * The contents of this file constitute Original Code as defined in and | |
7 | * are subject to the Apple Public Source License Version 1.1 (the | |
8 | * "License"). You may not use this file except in compliance with the | |
9 | * License. Please obtain a copy of the License at | |
10 | * http://www.apple.com/publicsource and read it before using this file. | |
11 | * | |
12 | * This Original Code and all software distributed under the License are | |
13 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the | |
17 | * License for the specific language governing rights and limitations | |
18 | * under the License. | |
19 | * | |
20 | * @APPLE_LICENSE_HEADER_END@ | |
21 | */ | |
22 | ||
0fae82ee A |
23 | /* |
24 | * Modification History | |
25 | * | |
26 | * June 1, 2001 Allan Nathanson <ajn@apple.com> | |
27 | * - public API conversion | |
28 | * | |
29 | * March 24, 2000 Allan Nathanson <ajn@apple.com> | |
30 | * - initial revision | |
31 | */ | |
32 | ||
5958d7c0 A |
33 | #include "configd.h" |
34 | #include "session.h" | |
35 | ||
0fae82ee A |
36 | |
37 | static __inline__ void | |
38 | my_CFDictionaryApplyFunction(CFDictionaryRef theDict, | |
39 | CFDictionaryApplierFunction applier, | |
40 | void *context) | |
5958d7c0 | 41 | { |
0fae82ee A |
42 | CFAllocatorRef myAllocator; |
43 | CFDictionaryRef myDict; | |
44 | ||
45 | myAllocator = CFGetAllocator(theDict); | |
46 | myDict = CFDictionaryCreateCopy(myAllocator, theDict); | |
47 | CFDictionaryApplyFunction(myDict, applier, context); | |
48 | CFRelease(myDict); | |
49 | return; | |
50 | } | |
51 | ||
52 | ||
53 | int | |
54 | __SCDynamicStoreAddWatchedKey(SCDynamicStoreRef store, CFStringRef key, Boolean isRegex) | |
55 | { | |
56 | SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; | |
5958d7c0 | 57 | |
0fae82ee A |
58 | SCLog(_configd_verbose, LOG_DEBUG, CFSTR("__SCDynamicStoreAddWatchedKey:")); |
59 | SCLog(_configd_verbose, LOG_DEBUG, CFSTR(" key = %@"), key); | |
60 | SCLog(_configd_verbose, LOG_DEBUG, CFSTR(" isRegex = %s"), isRegex ? "TRUE" : "FALSE"); | |
5958d7c0 | 61 | |
0fae82ee A |
62 | if (!store || (storePrivate->server == MACH_PORT_NULL)) { |
63 | return kSCStatusNoStoreSession; /* you must have an open session to play */ | |
5958d7c0 A |
64 | } |
65 | ||
66 | /* | |
67 | * add new key after checking if key has already been defined | |
68 | */ | |
0fae82ee A |
69 | if (isRegex) { |
70 | if (CFSetContainsValue(storePrivate->reKeys, key)) | |
71 | return kSCStatusKeyExists; /* sorry, key already exists in notifier list */ | |
72 | CFSetAddValue(storePrivate->reKeys, key); /* add key to this sessions notifier list */ | |
5958d7c0 | 73 | } else { |
0fae82ee A |
74 | if (CFSetContainsValue(storePrivate->keys, key)) |
75 | return kSCStatusKeyExists; /* sorry, key already exists in notifier list */ | |
76 | CFSetAddValue(storePrivate->keys, key); /* add key to this sessions notifier list */ | |
5958d7c0 A |
77 | } |
78 | ||
0fae82ee | 79 | if (isRegex) { |
5958d7c0 A |
80 | CFStringRef sessionKey; |
81 | int regexStrLen; | |
82 | char *regexStr; | |
83 | CFMutableDataRef regexData; | |
84 | int reError; | |
85 | char reErrBuf[256]; | |
86 | int reErrStrLen; | |
87 | addContext context; | |
88 | CFDictionaryRef info; | |
89 | CFMutableDictionaryRef newInfo; | |
90 | CFArrayRef rKeys; | |
91 | CFMutableArrayRef newRKeys; | |
92 | CFArrayRef rData; | |
93 | CFMutableArrayRef newRData; | |
94 | ||
95 | /* | |
96 | * We are adding a regex key. As such, we need to flag | |
0fae82ee | 97 | * any keys currently in the store. |
5958d7c0 A |
98 | */ |
99 | ||
100 | /* 1. Extract a C String version of the key pattern string. */ | |
101 | ||
102 | regexStrLen = CFStringGetLength(key) + 1; | |
103 | regexStr = CFAllocatorAllocate(NULL, regexStrLen, 0); | |
104 | if (!CFStringGetCString(key, | |
105 | regexStr, | |
106 | regexStrLen, | |
107 | kCFStringEncodingMacRoman)) { | |
0fae82ee | 108 | SCLog(_configd_verbose, LOG_DEBUG, CFSTR("CFStringGetCString: could not convert regex key to C string")); |
5958d7c0 | 109 | CFAllocatorDeallocate(NULL, regexStr); |
0fae82ee | 110 | return kSCStatusFailed; |
5958d7c0 A |
111 | } |
112 | ||
113 | /* 2. Compile the regular expression from the pattern string. */ | |
114 | ||
115 | regexData = CFDataCreateMutable(NULL, sizeof(regex_t)); | |
116 | CFDataSetLength(regexData, sizeof(regex_t)); | |
117 | reError = regcomp((regex_t *)CFDataGetBytePtr(regexData), | |
118 | regexStr, | |
119 | REG_EXTENDED); | |
120 | CFAllocatorDeallocate(NULL, regexStr); | |
121 | if (reError != 0) { | |
122 | reErrStrLen = regerror(reError, | |
123 | (regex_t *)CFDataGetBytePtr(regexData), | |
124 | reErrBuf, | |
125 | sizeof(reErrBuf)); | |
0fae82ee | 126 | SCLog(_configd_verbose, LOG_DEBUG, CFSTR("regcomp() key: %s"), reErrBuf); |
5958d7c0 | 127 | CFRelease(regexData); |
0fae82ee | 128 | return kSCStatusFailed; |
5958d7c0 A |
129 | } |
130 | ||
131 | /* | |
132 | * 3. Iterate over the current keys and add this session as a "watcher" | |
0fae82ee | 133 | * for any key already defined in the store. |
5958d7c0 A |
134 | */ |
135 | ||
0fae82ee A |
136 | context.store = storePrivate; |
137 | context.preg = (regex_t *)CFDataGetBytePtr(regexData); | |
138 | my_CFDictionaryApplyFunction(storeData, | |
139 | (CFDictionaryApplierFunction)_addRegexWatcherByKey, | |
140 | &context); | |
5958d7c0 A |
141 | |
142 | /* | |
143 | * 4. We also need to save this key and the associated regex data | |
144 | * for any subsequent additions. | |
145 | */ | |
0fae82ee | 146 | sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), storePrivate->server); |
5958d7c0 A |
147 | |
148 | info = CFDictionaryGetValue(sessionData, sessionKey); | |
149 | if (info) { | |
150 | newInfo = CFDictionaryCreateMutableCopy(NULL, 0, info); | |
151 | } else { | |
152 | newInfo = CFDictionaryCreateMutable(NULL, | |
153 | 0, | |
154 | &kCFTypeDictionaryKeyCallBacks, | |
155 | &kCFTypeDictionaryValueCallBacks); | |
156 | } | |
157 | ||
158 | rKeys = CFDictionaryGetValue(newInfo, kSCDRegexKeys); | |
159 | if ((rKeys == NULL) || | |
160 | (CFArrayContainsValue(rKeys, | |
161 | CFRangeMake(0, CFArrayGetCount(rKeys)), | |
162 | key) == FALSE)) { | |
163 | rData = CFDictionaryGetValue(newInfo, kSCDRegexData); | |
164 | if (rKeys) { | |
165 | newRKeys = CFArrayCreateMutableCopy(NULL, 0, rKeys); | |
166 | newRData = CFArrayCreateMutableCopy(NULL, 0, rData); | |
167 | } else { | |
168 | newRKeys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); | |
169 | newRData = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); | |
170 | } | |
171 | ||
172 | /* save the regex key */ | |
173 | CFArrayAppendValue(newRKeys, key); | |
174 | CFDictionarySetValue(newInfo, kSCDRegexKeys, newRKeys); | |
175 | CFRelease(newRKeys); | |
176 | /* ...and the compiled expression */ | |
177 | CFArrayAppendValue(newRData, regexData); | |
178 | CFDictionarySetValue(newInfo, kSCDRegexData, newRData); | |
179 | CFRelease(newRData); | |
180 | CFDictionarySetValue(sessionData, sessionKey, newInfo); | |
181 | } | |
a5f60add | 182 | CFRelease(regexData); |
5958d7c0 A |
183 | CFRelease(newInfo); |
184 | CFRelease(sessionKey); | |
185 | } else { | |
186 | CFNumberRef sessionNum; | |
187 | ||
188 | /* | |
189 | * We are watching a specific key. As such, update the | |
0fae82ee | 190 | * store to mark our interest in any changes. |
5958d7c0 | 191 | */ |
0fae82ee | 192 | sessionNum = CFNumberCreate(NULL, kCFNumberIntType, &storePrivate->server); |
5958d7c0 A |
193 | _addWatcher(sessionNum, key); |
194 | CFRelease(sessionNum); | |
195 | } | |
196 | ||
0fae82ee | 197 | return kSCStatusOK; |
5958d7c0 A |
198 | } |
199 | ||
200 | ||
201 | kern_return_t | |
202 | _notifyadd(mach_port_t server, | |
203 | xmlData_t keyRef, /* raw XML bytes */ | |
204 | mach_msg_type_number_t keyLen, | |
0fae82ee A |
205 | int isRegex, |
206 | int *sc_status | |
5958d7c0 A |
207 | ) |
208 | { | |
5958d7c0 | 209 | serverSessionRef mySession = getSession(server); |
5958d7c0 | 210 | CFStringRef key; /* key (un-serialized) */ |
5958d7c0 | 211 | |
0fae82ee A |
212 | SCLog(_configd_verbose, LOG_DEBUG, CFSTR("Add notification key for this session.")); |
213 | SCLog(_configd_verbose, LOG_DEBUG, CFSTR(" server = %d"), server); | |
5958d7c0 A |
214 | |
215 | /* un-serialize the key */ | |
a5f60add | 216 | if (!_SCUnserialize((CFPropertyListRef *)&key, (void *)keyRef, keyLen)) { |
0fae82ee A |
217 | *sc_status = kSCStatusFailed; |
218 | return KERN_SUCCESS; | |
a5f60add A |
219 | } |
220 | ||
221 | if (!isA_CFString(key)) { | |
222 | CFRelease(key); | |
0fae82ee | 223 | *sc_status = kSCStatusInvalidArgument; |
5958d7c0 A |
224 | return KERN_SUCCESS; |
225 | } | |
226 | ||
0fae82ee | 227 | *sc_status = __SCDynamicStoreAddWatchedKey(mySession->store, key, isRegex); |
5958d7c0 A |
228 | CFRelease(key); |
229 | ||
230 | return KERN_SUCCESS; | |
231 | } |