]> git.saurik.com Git - apple/configd.git/blob - configd.tproj/_notifyadd.c
configd-53.tar.gz
[apple/configd.git] / configd.tproj / _notifyadd.c
1 /*
2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
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
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
33 #include "configd.h"
34 #include "session.h"
35
36
37 static __inline__ void
38 my_CFDictionaryApplyFunction(CFDictionaryRef theDict,
39 CFDictionaryApplierFunction applier,
40 void *context)
41 {
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;
57
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");
61
62 if (!store || (storePrivate->server == MACH_PORT_NULL)) {
63 return kSCStatusNoStoreSession; /* you must have an open session to play */
64 }
65
66 /*
67 * add new key after checking if key has already been defined
68 */
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 */
73 } else {
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 */
77 }
78
79 if (isRegex) {
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
97 * any keys currently in the store.
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)) {
108 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("CFStringGetCString: could not convert regex key to C string"));
109 CFAllocatorDeallocate(NULL, regexStr);
110 return kSCStatusFailed;
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));
126 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("regcomp() key: %s"), reErrBuf);
127 CFRelease(regexData);
128 return kSCStatusFailed;
129 }
130
131 /*
132 * 3. Iterate over the current keys and add this session as a "watcher"
133 * for any key already defined in the store.
134 */
135
136 context.store = storePrivate;
137 context.preg = (regex_t *)CFDataGetBytePtr(regexData);
138 my_CFDictionaryApplyFunction(storeData,
139 (CFDictionaryApplierFunction)_addRegexWatcherByKey,
140 &context);
141
142 /*
143 * 4. We also need to save this key and the associated regex data
144 * for any subsequent additions.
145 */
146 sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), storePrivate->server);
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 }
182 CFRelease(regexData);
183 CFRelease(newInfo);
184 CFRelease(sessionKey);
185 } else {
186 CFNumberRef sessionNum;
187
188 /*
189 * We are watching a specific key. As such, update the
190 * store to mark our interest in any changes.
191 */
192 sessionNum = CFNumberCreate(NULL, kCFNumberIntType, &storePrivate->server);
193 _addWatcher(sessionNum, key);
194 CFRelease(sessionNum);
195 }
196
197 return kSCStatusOK;
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,
205 int isRegex,
206 int *sc_status
207 )
208 {
209 serverSessionRef mySession = getSession(server);
210 CFStringRef key; /* key (un-serialized) */
211
212 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("Add notification key for this session."));
213 SCLog(_configd_verbose, LOG_DEBUG, CFSTR(" server = %d"), server);
214
215 /* un-serialize the key */
216 if (!_SCUnserialize((CFPropertyListRef *)&key, (void *)keyRef, keyLen)) {
217 *sc_status = kSCStatusFailed;
218 return KERN_SUCCESS;
219 }
220
221 if (!isA_CFString(key)) {
222 CFRelease(key);
223 *sc_status = kSCStatusInvalidArgument;
224 return KERN_SUCCESS;
225 }
226
227 *sc_status = __SCDynamicStoreAddWatchedKey(mySession->store, key, isRegex);
228 CFRelease(key);
229
230 return KERN_SUCCESS;
231 }