]> git.saurik.com Git - apple/configd.git/blob - SystemConfiguration.fproj/SCDOpen.c
77352f520aed4688e9a4616b97783d6d41ab97bd
[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 /* allocate session */
250 size = sizeof(SCDynamicStorePrivate) - sizeof(CFRuntimeBase);
251 storePrivate = (SCDynamicStorePrivateRef)_CFRuntimeCreateInstance(allocator,
252 __kSCDynamicStoreTypeID,
253 size,
254 NULL);
255 if (storePrivate == NULL) {
256 _SCErrorSet(kSCStatusFailed);
257 return NULL;
258 }
259
260 /* server side of the "configd" session */
261 storePrivate->server = MACH_PORT_NULL;
262
263 /* flags */
264 storePrivate->locked = FALSE;
265 storePrivate->useSessionKeys = FALSE;
266
267 /* Notification status */
268 storePrivate->notifyStatus = NotifierNotRegistered;
269
270 /* "client" information associated with SCDynamicStoreCreateRunLoopSource() */
271 storePrivate->rlsRefs = 0;
272 storePrivate->rls = NULL;
273 storePrivate->rlsFunction = callout;
274 storePrivate->rlsContext.info = NULL;
275 storePrivate->rlsContext.retain = NULL;
276 storePrivate->rlsContext.release = NULL;
277 storePrivate->rlsContext.copyDescription = NULL;
278 if (context) {
279 bcopy(context, &storePrivate->rlsContext, sizeof(SCDynamicStoreContext));
280 if (context->retain != NULL) {
281 storePrivate->rlsContext.info = (void *)(*context->retain)(context->info);
282 }
283 }
284
285 /* "client" information associated with SCDynamicStoreNotifyCallback() */
286 storePrivate->callbackFunction = NULL;
287 storePrivate->callbackArgument = NULL;
288 storePrivate->callbackPort = NULL;
289 storePrivate->callbackRLS = NULL;
290
291 /* "server" information associated with SCDynamicStoreSetNotificationKeys() */
292 storePrivate->keys = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
293 storePrivate->patterns = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
294
295 /* "server" information associated with SCDynamicStoreNotifyMachPort(); */
296 storePrivate->notifyPort = MACH_PORT_NULL;
297 storePrivate->notifyPortIdentifier = 0;
298
299 /* "server" information associated with SCDynamicStoreNotifyFileDescriptor(); */
300 storePrivate->notifyFile = -1;
301 storePrivate->notifyFileIdentifier = 0;
302
303 /* "server" information associated with SCDynamicStoreNotifySignal(); */
304 storePrivate->notifySignal = 0;
305 storePrivate->notifySignalTask = TASK_NULL;
306
307 /* initialize global state */
308
309 pthread_mutex_lock(&_sc_lock);
310
311 /* get the server port */
312 if (_sc_server == MACH_PORT_NULL) {
313 char *server_name;
314 kern_return_t status;
315
316 server_name = getenv("SCD_SERVER");
317 if (!server_name) {
318 server_name = SCD_SERVER;
319 }
320
321 status = bootstrap_look_up(bootstrap_port, server_name, &_sc_server);
322 switch (status) {
323 case BOOTSTRAP_SUCCESS :
324 /* service currently registered, "a good thing" (tm) */
325 break;
326 case BOOTSTRAP_UNKNOWN_SERVICE :
327 /* service not currently registered, try again later */
328 sc_status = status;
329 goto done;
330 default :
331 #ifdef DEBUG
332 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("SCDynamicStoreCreate[WithOptions] bootstrap_look_up() failed: status=%d"), status);
333 #endif /* DEBUG */
334 sc_status = status;
335 goto done;
336 }
337 }
338
339 /* bump the number of active dynamic store sessions */
340 _sc_active++;
341
342 done :
343
344 pthread_mutex_unlock(&_sc_lock);
345
346 if (sc_status != kSCStatusOK) {
347 _SCErrorSet(sc_status);
348 CFRelease(storePrivate);
349 storePrivate = NULL;
350 }
351
352 return storePrivate;
353 }
354
355
356 const CFStringRef kSCDynamicStoreUseSessionKeys = CFSTR("UseSessionKeys"); /* CFBoolean */
357
358
359 SCDynamicStoreRef
360 SCDynamicStoreCreateWithOptions(CFAllocatorRef allocator,
361 CFStringRef name,
362 CFDictionaryRef storeOptions,
363 SCDynamicStoreCallBack callout,
364 SCDynamicStoreContext *context)
365 {
366 SCDynamicStorePrivateRef storePrivate;
367 kern_return_t status;
368 CFDataRef utfName; /* serialized name */
369 xmlData_t myNameRef;
370 CFIndex myNameLen;
371 CFDataRef xmlOptions = NULL; /* serialized options */
372 xmlData_t myOptionsRef = NULL;
373 CFIndex myOptionsLen = 0;
374 int sc_status = kSCStatusFailed;
375
376 /*
377 * allocate and initialize a new session
378 */
379 storePrivate = __SCDynamicStoreCreatePrivate(allocator, name, callout, context);
380 if (storePrivate == NULL) {
381 return NULL;
382 }
383
384 if (_sc_bundleID != NULL) {
385 CFStringRef fullName;
386
387 fullName = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@:%@"), _sc_bundleID, name);
388 name = fullName;
389 } else {
390 CFRetain(name);
391 }
392
393 if (!_SCSerializeString(name, &utfName, (void **)&myNameRef, &myNameLen)) {
394 CFRelease(name);
395 goto done;
396 }
397 CFRelease(name);
398
399 /* serialize the options */
400 if (storeOptions) {
401 if (!_SCSerialize(storeOptions, &xmlOptions, (void **)&myOptionsRef, &myOptionsLen)) {
402 CFRelease(utfName);
403 goto done;
404 }
405 }
406
407 /* open a new session with the server */
408 status = configopen(_sc_server,
409 myNameRef,
410 myNameLen,
411 myOptionsRef,
412 myOptionsLen,
413 &storePrivate->server,
414 (int *)&sc_status);
415
416 /* clean up */
417 CFRelease(utfName);
418 if (xmlOptions) CFRelease(xmlOptions);
419
420 if (status != KERN_SUCCESS) {
421 #ifdef DEBUG
422 if (status != MACH_SEND_INVALID_DEST)
423 SCLog(_sc_verbose, LOG_DEBUG, CFSTR("SCDynamicStoreCreate[WithOptions] configopen(): %s"), mach_error_string(status));
424 #endif /* DEBUG */
425 sc_status = status;
426 goto done;
427 }
428
429 done :
430
431 if (sc_status != kSCStatusOK) {
432 _SCErrorSet(sc_status);
433 CFRelease(storePrivate);
434 storePrivate = NULL;
435 }
436
437 return (SCDynamicStoreRef)storePrivate;
438 }
439
440
441 SCDynamicStoreRef
442 SCDynamicStoreCreate(CFAllocatorRef allocator,
443 CFStringRef name,
444 SCDynamicStoreCallBack callout,
445 SCDynamicStoreContext *context)
446 {
447 return SCDynamicStoreCreateWithOptions(allocator, name, NULL, callout, context);
448 }
449
450
451 CFTypeID
452 SCDynamicStoreGetTypeID(void) {
453 pthread_once(&initialized, __SCDynamicStoreInitialize); /* initialize runtime */
454 return __kSCDynamicStoreTypeID;
455 }