]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCDOpen.c
configd-137.2.tar.gz
[apple/configd.git] / SystemConfiguration.fproj / SCDOpen.c
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * Modification History
26 *
27 * June 1, 2001 Allan Nathanson <ajn@apple.com>
28 * - public API conversion
29 *
30 * March 24, 2000 Allan Nathanson <ajn@apple.com>
31 * - initial revision
32 */
33
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <sys/types.h>
37 #include <mach/mach.h>
38 #include <mach/mach_error.h>
39 #include <servers/bootstrap.h>
40
41 #include <SystemConfiguration/SystemConfiguration.h>
42 #include <SystemConfiguration/SCPrivate.h>
43 #include "SCDynamicStoreInternal.h"
44 #include "config.h" /* MiG generated file */
45
46
47 static int _sc_active = 0;
48 static CFStringRef _sc_bundleID = NULL;
49 static pthread_mutex_t _sc_lock = PTHREAD_MUTEX_INITIALIZER;
50 static mach_port_t _sc_server = MACH_PORT_NULL;
51
52
53 static CFStringRef
54 __SCDynamicStoreCopyDescription(CFTypeRef cf) {
55 CFAllocatorRef allocator = CFGetAllocator(cf);
56 CFMutableStringRef result;
57 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)cf;
58
59 result = CFStringCreateMutable(allocator, 0);
60 CFStringAppendFormat(result, NULL, CFSTR("<SCDynamicStore %p [%p]> { "), cf, allocator);
61 if (storePrivate->server != MACH_PORT_NULL) {
62 CFStringAppendFormat(result, NULL, CFSTR("server port=%d"), storePrivate->server);
63 } else {
64 CFStringAppendFormat(result, NULL, CFSTR("server not (no longer) available"));
65 }
66 if (storePrivate->locked) {
67 CFStringAppendFormat(result, NULL, CFSTR(", locked"));
68 }
69 switch (storePrivate->notifyStatus) {
70 case Using_NotifierWait :
71 CFStringAppendFormat(result, NULL, CFSTR(", waiting for a notification"));
72 break;
73 case Using_NotifierInformViaMachPort :
74 CFStringAppendFormat(result, NULL, CFSTR(", mach port notifications"));
75 break;
76 case Using_NotifierInformViaFD :
77 CFStringAppendFormat(result, NULL, CFSTR(", FD notifications"));
78 break;
79 case Using_NotifierInformViaSignal :
80 CFStringAppendFormat(result, NULL, CFSTR(", BSD signal notifications"));
81 break;
82 case Using_NotifierInformViaRunLoop :
83 case Using_NotifierInformViaCallback :
84 if (storePrivate->notifyStatus == Using_NotifierInformViaRunLoop) {
85 CFStringAppendFormat(result, NULL, CFSTR(", runloop notifications"));
86 CFStringAppendFormat(result, NULL, CFSTR(" (func=0x%8.8x"), storePrivate->rlsFunction);
87 CFStringAppendFormat(result, NULL, CFSTR(", info=0x%8.8x"), storePrivate->rlsContext.info);
88 CFStringAppendFormat(result, NULL, CFSTR(", rls=0x%8.8x" ), storePrivate->rls);
89 CFStringAppendFormat(result, NULL, CFSTR(", refs=%d" ), storePrivate->rlsRefs);
90 } else {
91 CFStringAppendFormat(result, NULL, CFSTR(", mach port/callback notifications"));
92 CFStringAppendFormat(result, NULL, CFSTR(" (func=0x%8.8x"), storePrivate->callbackFunction);
93 CFStringAppendFormat(result, NULL, CFSTR(", info=0x%8.8x"), storePrivate->callbackArgument);
94 }
95 if (storePrivate->callbackRLS != NULL) {
96 CFStringAppendFormat(result, NULL, CFSTR(", notify rls=%@" ), storePrivate->callbackRLS);
97 }
98 CFStringAppendFormat(result, NULL, CFSTR(")"));
99 break;
100 default :
101 CFStringAppendFormat(result, NULL, CFSTR(", notification delivery not requested%s"),
102 storePrivate->rlsFunction ? " (yet)" : "");
103 break;
104 }
105 CFStringAppendFormat(result, NULL, CFSTR(" }"));
106
107 return result;
108 }
109
110
111 static void
112 __SCDynamicStoreDeallocate(CFTypeRef cf)
113 {
114 int oldThreadState;
115 int sc_status;
116 kern_return_t status;
117 SCDynamicStoreRef store = (SCDynamicStoreRef)cf;
118 SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store;
119
120 (void) pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldThreadState);
121
122 /* Remove/cancel any outstanding notification requests. */
123 (void) SCDynamicStoreNotifyCancel(store);
124
125 if ((storePrivate->server != MACH_PORT_NULL) && storePrivate->locked) {
126 (void) SCDynamicStoreUnlock(store); /* release the lock */
127 }
128
129 if (storePrivate->server != MACH_PORT_NULL) {
130 status = configclose(storePrivate->server, (int *)&sc_status);
131 #ifdef DEBUG
132 if (status != KERN_SUCCESS) {
133 if (status != MACH_SEND_INVALID_DEST)
134 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("__SCDynamicStoreDeallocate configclose(): %s"), mach_error_string(status));
135 }
136 #endif /* DEBUG */
137
138 (void) mach_port_destroy(mach_task_self(), storePrivate->server);
139 storePrivate->server = MACH_PORT_NULL;
140 }
141
142 (void) pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldThreadState);
143 pthread_testcancel();
144
145 /* release any callback context info */
146 if (storePrivate->rlsContext.release != NULL) {
147 (*storePrivate->rlsContext.release)(storePrivate->rlsContext.info);
148 }
149
150 /* release any keys being watched */
151 CFRelease(storePrivate->keys);
152 CFRelease(storePrivate->patterns);
153
154 /* cleanup */
155 pthread_mutex_lock(&_sc_lock);
156 _sc_active--; /* drop the number of active dynamic store sessions */
157 if ((_sc_active == 0) && (_sc_server != MACH_PORT_NULL)) {
158 /* release the [last] reference to the server */
159 (void)mach_port_deallocate(mach_task_self(), _sc_server);
160 _sc_server = MACH_PORT_NULL;
161 }
162 pthread_mutex_unlock(&_sc_lock);
163
164 return;
165 }
166
167
168 static CFTypeID __kSCDynamicStoreTypeID = _kCFRuntimeNotATypeID;
169
170
171 static const CFRuntimeClass __SCDynamicStoreClass = {
172 0, // version
173 "SCDynamicStore", // className
174 NULL, // init
175 NULL, // copy
176 __SCDynamicStoreDeallocate, // dealloc
177 NULL, // equal
178 NULL, // hash
179 NULL, // copyFormattingDesc
180 __SCDynamicStoreCopyDescription // copyDebugDesc
181 };
182
183
184 static void
185 childForkHandler()
186 {
187 /* the process has forked (and we are the child process) */
188
189 _sc_active = 0;
190 _sc_server = MACH_PORT_NULL;
191
192 return;
193 }
194
195
196 static pthread_once_t initialized = PTHREAD_ONCE_INIT;
197
198 static void
199 __SCDynamicStoreInitialize(void) {
200 CFBundleRef bundle;
201
202 /* register with CoreFoundation */
203 __kSCDynamicStoreTypeID = _CFRuntimeRegisterClass(&__SCDynamicStoreClass);
204
205 /* add handler to cleanup after fork() */
206 (void) pthread_atfork(NULL, NULL, childForkHandler);
207
208 /* get the application/executable/bundle name */
209 bundle = CFBundleGetMainBundle();
210 if (bundle != NULL) {
211 _sc_bundleID = CFBundleGetIdentifier(bundle);
212 if (_sc_bundleID != NULL) {
213 CFRetain(_sc_bundleID);
214 } else {
215 CFURLRef url;
216
217 url = CFBundleCopyExecutableURL(bundle);
218 if (url != NULL) {
219 _sc_bundleID = CFURLCopyPath(url);
220 CFRelease(url);
221 }
222 }
223
224 if (_sc_bundleID != NULL) {
225 if (CFEqual(_sc_bundleID, CFSTR("/"))) {
226 CFRelease(_sc_bundleID);
227 _sc_bundleID = CFStringCreateWithFormat(NULL, NULL, CFSTR("(%d)"), getpid());
228 }
229 }
230 }
231
232 return;
233 }
234
235
236 SCDynamicStorePrivateRef
237 __SCDynamicStoreCreatePrivate(CFAllocatorRef allocator,
238 const CFStringRef name,
239 SCDynamicStoreCallBack callout,
240 SCDynamicStoreContext *context)
241 {
242 int sc_status = kSCStatusOK;
243 uint32_t size;
244 SCDynamicStorePrivateRef storePrivate;
245
246 /* initialize runtime */
247 pthread_once(&initialized, __SCDynamicStoreInitialize);
248
249
250 /* allocate session */
251 size = sizeof(SCDynamicStorePrivate) - sizeof(CFRuntimeBase);
252 storePrivate = (SCDynamicStorePrivateRef)_CFRuntimeCreateInstance(allocator,
253 __kSCDynamicStoreTypeID,
254 size,
255 NULL);
256 if (storePrivate == NULL) {
257 _SCErrorSet(kSCStatusFailed);
258 return NULL;
259 }
260
261 /* server side of the "configd" session */
262 storePrivate->server = MACH_PORT_NULL;
263
264 /* flags */
265 storePrivate->locked = FALSE;
266 storePrivate->useSessionKeys = FALSE;
267
268 /* Notification status */
269 storePrivate->notifyStatus = NotifierNotRegistered;
270
271 /* "client" information associated with SCDynamicStoreCreateRunLoopSource() */
272 storePrivate->rlsRefs = 0;
273 storePrivate->rls = NULL;
274 storePrivate->rlsFunction = callout;
275 storePrivate->rlsContext.info = NULL;
276 storePrivate->rlsContext.retain = NULL;
277 storePrivate->rlsContext.release = NULL;
278 storePrivate->rlsContext.copyDescription = NULL;
279 if (context) {
280 bcopy(context, &storePrivate->rlsContext, sizeof(SCDynamicStoreContext));
281 if (context->retain != NULL) {
282 storePrivate->rlsContext.info = (void *)(*context->retain)(context->info);
283 }
284 }
285
286 /* "client" information associated with SCDynamicStoreNotifyCallback() */
287 storePrivate->callbackFunction = NULL;
288 storePrivate->callbackArgument = NULL;
289 storePrivate->callbackPort = NULL;
290 storePrivate->callbackRLS = NULL;
291
292 /* "server" information associated with SCDynamicStoreSetNotificationKeys() */
293 storePrivate->keys = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
294 storePrivate->patterns = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
295
296 /* "server" information associated with SCDynamicStoreNotifyMachPort(); */
297 storePrivate->notifyPort = MACH_PORT_NULL;
298 storePrivate->notifyPortIdentifier = 0;
299
300 /* "server" information associated with SCDynamicStoreNotifyFileDescriptor(); */
301 storePrivate->notifyFile = -1;
302 storePrivate->notifyFileIdentifier = 0;
303
304 /* "server" information associated with SCDynamicStoreNotifySignal(); */
305 storePrivate->notifySignal = 0;
306 storePrivate->notifySignalTask = TASK_NULL;
307
308 /* initialize global state */
309
310 pthread_mutex_lock(&_sc_lock);
311
312 /* get the server port */
313 if (_sc_server == MACH_PORT_NULL) {
314 char *server_name;
315 kern_return_t status;
316
317 server_name = getenv("SCD_SERVER");
318 if (!server_name) {
319 server_name = SCD_SERVER;
320 }
321
322 status = bootstrap_look_up(bootstrap_port, server_name, &_sc_server);
323 switch (status) {
324 case BOOTSTRAP_SUCCESS :
325 /* service currently registered, "a good thing" (tm) */
326 break;
327 case BOOTSTRAP_UNKNOWN_SERVICE :
328 /* service not currently registered, try again later */
329 sc_status = status;
330 goto done;
331 default :
332 #ifdef DEBUG
333 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("SCDynamicStoreCreate[WithOptions] bootstrap_look_up() failed: status=%d"), status);
334 #endif /* DEBUG */
335 sc_status = status;
336 goto done;
337 }
338 }
339
340 /* bump the number of active dynamic store sessions */
341 _sc_active++;
342
343 done :
344
345 pthread_mutex_unlock(&_sc_lock);
346
347 if (sc_status != kSCStatusOK) {
348 _SCErrorSet(sc_status);
349 CFRelease(storePrivate);
350 storePrivate = NULL;
351 }
352
353 return storePrivate;
354 }
355
356
357 const CFStringRef kSCDynamicStoreUseSessionKeys = CFSTR("UseSessionKeys"); /* CFBoolean */
358
359
360 SCDynamicStoreRef
361 SCDynamicStoreCreateWithOptions(CFAllocatorRef allocator,
362 CFStringRef name,
363 CFDictionaryRef storeOptions,
364 SCDynamicStoreCallBack callout,
365 SCDynamicStoreContext *context)
366 {
367 SCDynamicStorePrivateRef storePrivate;
368 kern_return_t status;
369 CFDataRef utfName; /* serialized name */
370 xmlData_t myNameRef;
371 CFIndex myNameLen;
372 CFDataRef xmlOptions = NULL; /* serialized options */
373 xmlData_t myOptionsRef = NULL;
374 CFIndex myOptionsLen = 0;
375 int sc_status = kSCStatusFailed;
376
377 /*
378 * allocate and initialize a new session
379 */
380 storePrivate = __SCDynamicStoreCreatePrivate(allocator, name, callout, context);
381 if (storePrivate == NULL) {
382 return NULL;
383 }
384
385 if (_sc_bundleID != NULL) {
386 CFStringRef fullName;
387
388 fullName = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@:%@"), _sc_bundleID, name);
389 name = fullName;
390 } else {
391 CFRetain(name);
392 }
393
394 if (!_SCSerializeString(name, &utfName, (void **)&myNameRef, &myNameLen)) {
395 CFRelease(name);
396 goto done;
397 }
398 CFRelease(name);
399
400 /* serialize the options */
401 if (storeOptions) {
402 if (!_SCSerialize(storeOptions, &xmlOptions, (void **)&myOptionsRef, &myOptionsLen)) {
403 CFRelease(utfName);
404 goto done;
405 }
406 }
407
408 /* open a new session with the server */
409 status = configopen(_sc_server,
410 myNameRef,
411 myNameLen,
412 myOptionsRef,
413 myOptionsLen,
414 &storePrivate->server,
415 (int *)&sc_status);
416
417 /* clean up */
418 CFRelease(utfName);
419 if (xmlOptions) CFRelease(xmlOptions);
420
421 if (status != KERN_SUCCESS) {
422 #ifdef DEBUG
423 if (status != MACH_SEND_INVALID_DEST)
424 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("SCDynamicStoreCreate[WithOptions] configopen(): %s"), mach_error_string(status));
425 #endif /* DEBUG */
426 sc_status = status;
427 goto done;
428 }
429
430 done :
431
432 if (sc_status != kSCStatusOK) {
433 _SCErrorSet(sc_status);
434 CFRelease(storePrivate);
435 storePrivate = NULL;
436 }
437
438 return (SCDynamicStoreRef)storePrivate;
439 }
440
441
442 SCDynamicStoreRef
443 SCDynamicStoreCreate(CFAllocatorRef allocator,
444 CFStringRef name,
445 SCDynamicStoreCallBack callout,
446 SCDynamicStoreContext *context)
447 {
448 return SCDynamicStoreCreateWithOptions(allocator, name, NULL, callout, context);
449 }
450
451
452 CFTypeID
453 SCDynamicStoreGetTypeID(void) {
454 pthread_once(&initialized, __SCDynamicStoreInitialize); /* initialize runtime */
455 return __kSCDynamicStoreTypeID;
456 }