]> git.saurik.com Git - apple/configd.git/blame - configd.tproj/_SCD.c
configd-137.3.tar.gz
[apple/configd.git] / configd.tproj / _SCD.c
CommitLineData
5958d7c0 1/*
dbf6a266 2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
5958d7c0
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
009ee3c6 5 *
009ee3c6
A
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
5958d7c0
A
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
009ee3c6
A
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 *
5958d7c0
A
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
0fae82ee
A
24/*
25 * Modification History
26 *
27 * June 1, 2001 Allan Nathanson <ajn@apple.com>
28 * - public API conversion
29 *
30 * June 2, 2000 Allan Nathanson <ajn@apple.com>
31 * - initial revision
32 */
33
5958d7c0 34
dbf6a266
A
35#include <unistd.h>
36
5958d7c0 37#include "configd.h"
dbf6a266
A
38#include "configd_server.h"
39#include "session.h"
5958d7c0
A
40
41
009ee3c6 42__private_extern__ CFMutableDictionaryRef sessionData = NULL;
0fae82ee 43
009ee3c6
A
44__private_extern__ CFMutableDictionaryRef storeData = NULL;
45__private_extern__ CFMutableDictionaryRef storeData_s = NULL;
5958d7c0 46
009ee3c6
A
47__private_extern__ CFMutableDictionaryRef patternData = NULL;
48__private_extern__ CFMutableDictionaryRef patternData_s = NULL;
5958d7c0 49
009ee3c6
A
50__private_extern__ CFMutableSetRef changedKeys = NULL;
51__private_extern__ CFMutableSetRef changedKeys_s = NULL;
5958d7c0 52
009ee3c6
A
53__private_extern__ CFMutableSetRef deferredRemovals = NULL;
54__private_extern__ CFMutableSetRef deferredRemovals_s = NULL;
5958d7c0 55
009ee3c6
A
56__private_extern__ CFMutableSetRef removedSessionKeys = NULL;
57__private_extern__ CFMutableSetRef removedSessionKeys_s = NULL;
5958d7c0 58
009ee3c6 59__private_extern__ CFMutableSetRef needsNotification = NULL;
5958d7c0 60
009ee3c6 61__private_extern__ int storeLocked = 0; /* > 0 if dynamic store locked */
5958d7c0 62
009ee3c6
A
63
64__private_extern__
5958d7c0 65void
0fae82ee 66_swapLockedStoreData()
5958d7c0
A
67{
68 void *temp;
69
0fae82ee
A
70 temp = storeData;
71 storeData = storeData_s;
72 storeData_s = temp;
5958d7c0 73
009ee3c6
A
74 temp = patternData;
75 patternData = patternData_s;
76 patternData_s = temp;
77
5958d7c0
A
78 temp = changedKeys;
79 changedKeys = changedKeys_s;
80 changedKeys_s = temp;
81
82 temp = deferredRemovals;
83 deferredRemovals = deferredRemovals_s;
84 deferredRemovals_s = temp;
85
86 temp = removedSessionKeys;
87 removedSessionKeys = removedSessionKeys_s;
88 removedSessionKeys_s = temp;
89
90 return;
91}
92
93
009ee3c6 94__private_extern__
5958d7c0
A
95void
96_addWatcher(CFNumberRef sessionNum, CFStringRef watchedKey)
97{
98 CFDictionaryRef dict;
99 CFMutableDictionaryRef newDict;
100 CFArrayRef watchers;
101 CFMutableArrayRef newWatchers;
102 CFArrayRef watcherRefs;
103 CFMutableArrayRef newWatcherRefs;
104 CFIndex i;
105 int refCnt;
106 CFNumberRef refNum;
107
108 /*
0fae82ee 109 * Get the dictionary associated with this key out of the store
5958d7c0 110 */
0fae82ee 111 dict = CFDictionaryGetValue(storeData, watchedKey);
5958d7c0
A
112 if (dict) {
113 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
114 } else {
115 newDict = CFDictionaryCreateMutable(NULL,
116 0,
117 &kCFTypeDictionaryKeyCallBacks,
118 &kCFTypeDictionaryValueCallBacks);
119 }
120
121 /*
122 * Get the set of watchers out of the keys dictionary
123 */
124 watchers = CFDictionaryGetValue(newDict, kSCDWatchers);
125 watcherRefs = CFDictionaryGetValue(newDict, kSCDWatcherRefs);
126 if (watchers) {
127 newWatchers = CFArrayCreateMutableCopy(NULL, 0, watchers);
128 newWatcherRefs = CFArrayCreateMutableCopy(NULL, 0, watcherRefs);
129 } else {
130 newWatchers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
131 newWatcherRefs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
132 }
133
134 /*
135 * Add my session to the set of watchers
136 */
137 i = CFArrayGetFirstIndexOfValue(newWatchers,
138 CFRangeMake(0, CFArrayGetCount(newWatchers)),
139 sessionNum);
dbf6a266 140 if (i == kCFNotFound) {
5958d7c0
A
141 /* if this is the first instance of this session watching this key */
142 CFArrayAppendValue(newWatchers, sessionNum);
143 refCnt = 1;
144 refNum = CFNumberCreate(NULL, kCFNumberIntType, &refCnt);
145 CFArrayAppendValue(newWatcherRefs, refNum);
146 CFRelease(refNum);
147 } else {
148 /* if this is another instance of this session watching this key */
149 refNum = CFArrayGetValueAtIndex(newWatcherRefs, i);
150 CFNumberGetValue(refNum, kCFNumberIntType, &refCnt);
151 refCnt++;
152 refNum = CFNumberCreate(NULL, kCFNumberIntType, &refCnt);
153 CFArraySetValueAtIndex(newWatcherRefs, i, refNum);
154 CFRelease(refNum);
155 }
156
157 /*
158 * Update the keys dictionary
159 */
160 CFDictionarySetValue(newDict, kSCDWatchers, newWatchers);
161 CFRelease(newWatchers);
162 CFDictionarySetValue(newDict, kSCDWatcherRefs, newWatcherRefs);
163 CFRelease(newWatcherRefs);
164
165 /*
0fae82ee 166 * Update the store for this key
5958d7c0 167 */
0fae82ee 168 CFDictionarySetValue(storeData, watchedKey, newDict);
5958d7c0
A
169 CFRelease(newDict);
170
dbf6a266 171#ifdef DEBUG
0fae82ee 172 SCLog(_configd_verbose, LOG_DEBUG, CFSTR(" _addWatcher: %@, %@"), sessionNum, watchedKey);
dbf6a266 173#endif /* DEBUG */
5958d7c0
A
174
175 return;
176}
177
178
009ee3c6 179__private_extern__
5958d7c0
A
180void
181_removeWatcher(CFNumberRef sessionNum, CFStringRef watchedKey)
182{
183 CFDictionaryRef dict;
184 CFMutableDictionaryRef newDict;
185 CFArrayRef watchers;
186 CFMutableArrayRef newWatchers;
187 CFArrayRef watcherRefs;
188 CFMutableArrayRef newWatcherRefs;
189 CFIndex i;
190 int refCnt;
191 CFNumberRef refNum;
192
193 /*
0fae82ee 194 * Get the dictionary associated with this key out of the store
5958d7c0 195 */
0fae82ee 196 dict = CFDictionaryGetValue(storeData, watchedKey);
5958d7c0
A
197 if ((dict == NULL) || (CFDictionaryContainsKey(dict, kSCDWatchers) == FALSE)) {
198 /* key doesn't exist (isn't this really fatal?) */
dbf6a266 199#ifdef DEBUG
0fae82ee 200 SCLog(_configd_verbose, LOG_DEBUG, CFSTR(" _removeWatcher: %@, %@, key not watched"), sessionNum, watchedKey);
dbf6a266 201#endif /* DEBUG */
5958d7c0
A
202 return;
203 }
204 newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
205
206 /*
207 * Get the set of watchers out of the keys dictionary and
208 * remove this session from the list.
209 */
210 watchers = CFDictionaryGetValue(newDict, kSCDWatchers);
211 newWatchers = CFArrayCreateMutableCopy(NULL, 0, watchers);
212
213 watcherRefs = CFDictionaryGetValue(newDict, kSCDWatcherRefs);
214 newWatcherRefs = CFArrayCreateMutableCopy(NULL, 0, watcherRefs);
215
216 /* locate the session reference */
217 i = CFArrayGetFirstIndexOfValue(newWatchers,
218 CFRangeMake(0, CFArrayGetCount(newWatchers)),
219 sessionNum);
dbf6a266
A
220 if (i == kCFNotFound) {
221#ifdef DEBUG
0fae82ee 222 SCLog(_configd_verbose, LOG_DEBUG, CFSTR(" _removeWatcher: %@, %@, session not watching"), sessionNum, watchedKey);
dbf6a266 223#endif /* DEBUG */
5958d7c0
A
224 CFRelease(newDict);
225 CFRelease(newWatchers);
226 CFRelease(newWatcherRefs);
227 return;
228 }
229
230 /* remove one session reference */
231 refNum = CFArrayGetValueAtIndex(newWatcherRefs, i);
232 CFNumberGetValue(refNum, kCFNumberIntType, &refCnt);
233 if (--refCnt > 0) {
234 refNum = CFNumberCreate(NULL, kCFNumberIntType, &refCnt);
235 CFArraySetValueAtIndex(newWatcherRefs, i, refNum);
236 CFRelease(refNum);
237 } else {
238 /* if this was the last reference */
239 CFArrayRemoveValueAtIndex(newWatchers, i);
240 CFArrayRemoveValueAtIndex(newWatcherRefs, i);
241 }
242
243 if (CFArrayGetCount(newWatchers) > 0) {
244 /* if this key is still being "watched" */
245 CFDictionarySetValue(newDict, kSCDWatchers, newWatchers);
246 CFDictionarySetValue(newDict, kSCDWatcherRefs, newWatcherRefs);
247 } else {
248 /* no watchers left, remove the empty set */
249 CFDictionaryRemoveValue(newDict, kSCDWatchers);
250 CFDictionaryRemoveValue(newDict, kSCDWatcherRefs);
251 }
252 CFRelease(newWatchers);
253 CFRelease(newWatcherRefs);
254
255 if (CFDictionaryGetCount(newDict) > 0) {
256 /* if this key is still active */
0fae82ee 257 CFDictionarySetValue(storeData, watchedKey, newDict);
5958d7c0
A
258 } else {
259 /* no information left, remove the empty dictionary */
0fae82ee 260 CFDictionaryRemoveValue(storeData, watchedKey);
5958d7c0
A
261 }
262 CFRelease(newDict);
263
dbf6a266 264#ifdef DEBUG
0fae82ee 265 SCLog(_configd_verbose, LOG_DEBUG, CFSTR(" _removeWatcher: %@, %@"), sessionNum, watchedKey);
dbf6a266
A
266#endif /* DEBUG */
267
268 return;
269}
270
271
272__private_extern__
273void
274pushNotifications()
275{
276 const void **sessionsToNotify;
277 CFIndex notifyCnt;
278 int server;
279 serverSessionRef theSession;
280 SCDynamicStorePrivateRef storePrivate;
281
282 if (needsNotification == NULL)
283 return; /* if no sessions need to be kicked */
284
285 notifyCnt = CFSetGetCount(needsNotification);
286 sessionsToNotify = malloc(notifyCnt * sizeof(CFNumberRef));
287 CFSetGetValues(needsNotification, sessionsToNotify);
288 while (--notifyCnt >= 0) {
289 (void) CFNumberGetValue(sessionsToNotify[notifyCnt],
290 kCFNumberIntType,
291 &server);
292 theSession = getSession(server);
293 storePrivate = (SCDynamicStorePrivateRef)theSession->store;
294
295 /*
296 * deliver notifications to client sessions
297 */
298 if ((storePrivate->notifyStatus == Using_NotifierInformViaMachPort) &&
299 (storePrivate->notifyPort != MACH_PORT_NULL)) {
300 mach_msg_empty_send_t msg;
301 mach_msg_option_t options;
302 kern_return_t status;
303 /*
304 * Post notification as mach message
305 */
306#ifdef DEBUG
307 if (_configd_verbose) {
308 SCLog(TRUE, LOG_DEBUG, CFSTR("sending mach message notification."));
309 SCLog(TRUE, LOG_DEBUG, CFSTR(" port = %d"), storePrivate->notifyPort);
310 SCLog(TRUE, LOG_DEBUG, CFSTR(" msgid = %d"), storePrivate->notifyPortIdentifier);
311 }
312#endif /* DEBUG */
313 msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
314 msg.header.msgh_size = sizeof(msg);
315 msg.header.msgh_remote_port = storePrivate->notifyPort;
316 msg.header.msgh_local_port = MACH_PORT_NULL;
317 msg.header.msgh_id = storePrivate->notifyPortIdentifier;
318 options = MACH_SEND_TIMEOUT;
319 status = mach_msg(&msg.header, /* msg */
320 MACH_SEND_MSG|options, /* options */
321 msg.header.msgh_size, /* send_size */
322 0, /* rcv_size */
323 MACH_PORT_NULL, /* rcv_name */
324 0, /* timeout */
325 MACH_PORT_NULL); /* notify */
326 if (status == MACH_SEND_TIMED_OUT) {
327 mach_msg_destroy(&msg.header);
328 }
329 }
330
331 if ((storePrivate->notifyStatus == Using_NotifierInformViaFD) &&
332 (storePrivate->notifyFile >= 0)) {
333 ssize_t written;
334
335#ifdef DEBUG
336 if (_configd_verbose) {
337 SCLog(TRUE, LOG_DEBUG, CFSTR("sending (UNIX domain) socket notification"));
338 SCLog(TRUE, LOG_DEBUG, CFSTR(" fd = %d"), storePrivate->notifyFile);
339 SCLog(TRUE, LOG_DEBUG, CFSTR(" msgid = %d"), storePrivate->notifyFileIdentifier);
340 }
341#endif /* DEBUG */
342
343 written = write(storePrivate->notifyFile,
344 &storePrivate->notifyFileIdentifier,
345 sizeof(storePrivate->notifyFileIdentifier));
346 if (written == -1) {
347 if (errno == EWOULDBLOCK) {
348#ifdef DEBUG
349 SCLog(_configd_verbose, LOG_DEBUG,
350 CFSTR("sorry, only one outstanding notification per session."));
351#endif /* DEBUG */
352 } else {
353#ifdef DEBUG
354 SCLog(_configd_verbose, LOG_DEBUG,
355 CFSTR("could not send notification, write() failed: %s"),
356 strerror(errno));
357#endif /* DEBUG */
358 storePrivate->notifyFile = -1;
359 }
360 } else if (written != sizeof(storePrivate->notifyFileIdentifier)) {
361#ifdef DEBUG
362 SCLog(_configd_verbose, LOG_DEBUG,
363 CFSTR("could not send notification, incomplete write()"));
364#endif /* DEBUG */
365 storePrivate->notifyFile = -1;
366 }
367 }
368
369 if ((storePrivate->notifyStatus == Using_NotifierInformViaSignal) &&
370 (storePrivate->notifySignal > 0)) {
371 kern_return_t status;
372 pid_t pid;
373 /*
374 * Post notification as signal
375 */
376 status = pid_for_task(storePrivate->notifySignalTask, &pid);
377 if (status == KERN_SUCCESS) {
378#ifdef DEBUG
379 if (_configd_verbose) {
380 SCLog(TRUE, LOG_DEBUG, CFSTR("sending signal notification"));
381 SCLog(TRUE, LOG_DEBUG, CFSTR(" pid = %d"), pid);
382 SCLog(TRUE, LOG_DEBUG, CFSTR(" signal = %d"), storePrivate->notifySignal);
383 }
384#endif /* DEBUG */
385 if (kill(pid, storePrivate->notifySignal) != 0) {
386#ifdef DEBUG
387 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("could not send signal: %s"), strerror(errno));
388#endif /* DEBUG */
389 status = KERN_FAILURE;
390 }
391 } else {
392 mach_port_type_t pt;
393
394 if ((mach_port_type(mach_task_self(), storePrivate->notifySignalTask, &pt) == KERN_SUCCESS) &&
395 (pt & MACH_PORT_TYPE_DEAD_NAME)) {
396 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("could not send signal, process died"));
397 } else {
398 SCLog(_configd_verbose, LOG_DEBUG, CFSTR("could not send signal: %s"), mach_error_string(status));
399 }
400 }
401
402 if (status != KERN_SUCCESS) {
403 /* don't bother with any more attempts */
404 (void) mach_port_destroy(mach_task_self(), storePrivate->notifySignalTask);
405 storePrivate->notifySignal = 0;
406 storePrivate->notifySignalTask = TASK_NULL;
407 }
408 }
409 }
410 free(sessionsToNotify);
411
412 /*
413 * this list of notifications have been posted, wait for some more.
414 */
415 CFRelease(needsNotification);
416 needsNotification = NULL;
5958d7c0
A
417
418 return;
419}