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