]> git.saurik.com Git - apple/configd.git/blob - configd.tproj/_notifyadd.c
configd-24.tar.gz
[apple/configd.git] / configd.tproj / _notifyadd.c
1 /*
2 * Copyright (c) 2000 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 #include "configd.h"
24 #include "session.h"
25
26 SCDStatus
27 _SCDNotifierAdd(SCDSessionRef session, CFStringRef key, int regexOptions)
28 {
29 SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
30
31 SCDLog(LOG_DEBUG, CFSTR("_SCDNotifierAdd:"));
32 SCDLog(LOG_DEBUG, CFSTR(" key = %@"), key);
33 SCDLog(LOG_DEBUG, CFSTR(" regexOptions = %0o"), regexOptions);
34
35 if ((session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
36 return SCD_NOSESSION; /* you can't do anything with a closed session */
37 }
38
39 /*
40 * add new key after checking if key has already been defined
41 */
42 if (regexOptions & kSCDRegexKey) {
43 if (CFSetContainsValue(sessionPrivate->reKeys, key))
44 return SCD_EXISTS; /* sorry, key already exists in notifier list */
45 CFSetAddValue(sessionPrivate->reKeys, key); /* add key to this sessions notifier list */
46 } else {
47 if (CFSetContainsValue(sessionPrivate->keys, key))
48 return SCD_EXISTS; /* sorry, key already exists in notifier list */
49 CFSetAddValue(sessionPrivate->keys, key); /* add key to this sessions notifier list */
50 }
51
52 if (regexOptions & kSCDRegexKey) {
53 CFStringRef sessionKey;
54 int regexStrLen;
55 char *regexStr;
56 CFMutableDataRef regexData;
57 int reError;
58 char reErrBuf[256];
59 int reErrStrLen;
60 addContext context;
61 CFDictionaryRef info;
62 CFMutableDictionaryRef newInfo;
63 CFArrayRef rKeys;
64 CFMutableArrayRef newRKeys;
65 CFArrayRef rData;
66 CFMutableArrayRef newRData;
67
68 /*
69 * We are adding a regex key. As such, we need to flag
70 * any keys currently in the cache.
71 */
72
73 /* 1. Extract a C String version of the key pattern string. */
74
75 regexStrLen = CFStringGetLength(key) + 1;
76 regexStr = CFAllocatorAllocate(NULL, regexStrLen, 0);
77 if (!CFStringGetCString(key,
78 regexStr,
79 regexStrLen,
80 kCFStringEncodingMacRoman)) {
81 SCDLog(LOG_DEBUG, CFSTR("CFStringGetCString: could not convert regex key to C string"));
82 CFAllocatorDeallocate(NULL, regexStr);
83 return SCD_FAILED;
84 }
85
86 /* 2. Compile the regular expression from the pattern string. */
87
88 regexData = CFDataCreateMutable(NULL, sizeof(regex_t));
89 CFDataSetLength(regexData, sizeof(regex_t));
90 reError = regcomp((regex_t *)CFDataGetBytePtr(regexData),
91 regexStr,
92 REG_EXTENDED);
93 CFAllocatorDeallocate(NULL, regexStr);
94 if (reError != 0) {
95 reErrStrLen = regerror(reError,
96 (regex_t *)CFDataGetBytePtr(regexData),
97 reErrBuf,
98 sizeof(reErrBuf));
99 SCDLog(LOG_DEBUG, CFSTR("regcomp() key: %s"), reErrBuf);
100 CFRelease(regexData);
101 return SCD_FAILED;
102 }
103
104 /*
105 * 3. Iterate over the current keys and add this session as a "watcher"
106 * for any key already defined in the cache.
107 */
108
109 context.session = sessionPrivate;
110 context.preg = (regex_t *)CFDataGetBytePtr(regexData);
111 CFDictionaryApplyFunction(cacheData,
112 (CFDictionaryApplierFunction)_addRegexWatcherByKey,
113 &context);
114
115 /*
116 * 4. We also need to save this key and the associated regex data
117 * for any subsequent additions.
118 */
119 sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), sessionPrivate->server);
120
121 info = CFDictionaryGetValue(sessionData, sessionKey);
122 if (info) {
123 newInfo = CFDictionaryCreateMutableCopy(NULL, 0, info);
124 } else {
125 newInfo = CFDictionaryCreateMutable(NULL,
126 0,
127 &kCFTypeDictionaryKeyCallBacks,
128 &kCFTypeDictionaryValueCallBacks);
129 }
130
131 rKeys = CFDictionaryGetValue(newInfo, kSCDRegexKeys);
132 if ((rKeys == NULL) ||
133 (CFArrayContainsValue(rKeys,
134 CFRangeMake(0, CFArrayGetCount(rKeys)),
135 key) == FALSE)) {
136 rData = CFDictionaryGetValue(newInfo, kSCDRegexData);
137 if (rKeys) {
138 newRKeys = CFArrayCreateMutableCopy(NULL, 0, rKeys);
139 newRData = CFArrayCreateMutableCopy(NULL, 0, rData);
140 } else {
141 newRKeys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
142 newRData = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
143 }
144
145 /* save the regex key */
146 CFArrayAppendValue(newRKeys, key);
147 CFDictionarySetValue(newInfo, kSCDRegexKeys, newRKeys);
148 CFRelease(newRKeys);
149 /* ...and the compiled expression */
150 CFArrayAppendValue(newRData, regexData);
151 CFDictionarySetValue(newInfo, kSCDRegexData, newRData);
152 CFRelease(newRData);
153 CFDictionarySetValue(sessionData, sessionKey, newInfo);
154 }
155 CFRelease(newInfo);
156 CFRelease(sessionKey);
157 } else {
158 CFNumberRef sessionNum;
159
160 /*
161 * We are watching a specific key. As such, update the
162 * cache to mark our interest in any changes.
163 */
164 sessionNum = CFNumberCreate(NULL, kCFNumberIntType, &sessionPrivate->server);
165 _addWatcher(sessionNum, key);
166 CFRelease(sessionNum);
167 }
168
169 return SCD_OK;
170 }
171
172
173 kern_return_t
174 _notifyadd(mach_port_t server,
175 xmlData_t keyRef, /* raw XML bytes */
176 mach_msg_type_number_t keyLen,
177 int regexOptions,
178 int *scd_status
179 )
180 {
181 kern_return_t status;
182 serverSessionRef mySession = getSession(server);
183 CFDataRef xmlKey; /* key (XML serialized) */
184 CFStringRef key; /* key (un-serialized) */
185 CFStringRef xmlError;
186
187 SCDLog(LOG_DEBUG, CFSTR("Add notification key for this session."));
188 SCDLog(LOG_DEBUG, CFSTR(" server = %d"), server);
189
190 /* un-serialize the key */
191 xmlKey = CFDataCreate(NULL, keyRef, keyLen);
192 status = vm_deallocate(mach_task_self(), (vm_address_t)keyRef, keyLen);
193 if (status != KERN_SUCCESS) {
194 SCDLog(LOG_DEBUG, CFSTR("vm_deallocate(): %s"), mach_error_string(status));
195 /* non-fatal???, proceed */
196 }
197 key = CFPropertyListCreateFromXMLData(NULL,
198 xmlKey,
199 kCFPropertyListImmutable,
200 &xmlError);
201 CFRelease(xmlKey);
202 if (xmlError) {
203 SCDLog(LOG_DEBUG, CFSTR("CFPropertyListCreateFromXMLData() key: %s"), xmlError);
204 *scd_status = SCD_FAILED;
205 return KERN_SUCCESS;
206 }
207
208 *scd_status = _SCDNotifierAdd(mySession->session, key, regexOptions);
209 CFRelease(key);
210
211 return KERN_SUCCESS;
212 }