]> git.saurik.com Git - apple/configd.git/blob - SCMonitor/monitor.c
0afa500b85f5c64f0ba2a7193bb9c7bebd7820c1
[apple/configd.git] / SCMonitor / monitor.c
1 /*
2 * Copyright (c) 2007 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 * October 24, 2007 Allan Nathanson <ajn@apple.com>
28 * - initial revision
29 */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <CoreFoundation/CoreFoundation.h>
35 #include <SystemConfiguration/SystemConfiguration.h>
36 #include <SystemConfiguration/SCPrivate.h>
37 #include <ApplicationServices/ApplicationServices.h>
38 #include "UserEventAgentInterface.h"
39
40 #define MY_BUNDLE_ID CFSTR("com.apple.SystemConfiguration.SCMonitor")
41 #define MY_ICON_PATH "/System/Library/PreferencePanes/Network.prefPane/Contents/Resources/Network.icns"
42
43 #define NETWORK_PREF_APP "/System/Library/PreferencePanes/Network.prefPane"
44 #define NETWORK_PREF_CMD "New Interface"
45
46 typedef struct {
47 UserEventAgentInterfaceStruct *_UserEventAgentInterface;
48 CFUUIDRef _factoryID;
49 UInt32 _refCount;
50
51 Boolean no_user_intervention;
52
53 CFRunLoopSourceRef monitorRls;
54
55 CFMutableSetRef knownInterfaces;
56
57 CFMutableArrayRef userInterfaces;
58 CFUserNotificationRef userNotification;
59 CFRunLoopSourceRef userRls;
60 } MyType;
61
62 static CFMutableDictionaryRef notify_to_instance = NULL;
63
64
65 #pragma mark -
66 #pragma mark Watch for new [network] interfaces
67
68
69 static void
70 open_NetworkPrefPane(void)
71 {
72 AEDesc aeDesc = { typeNull, NULL };
73 CFArrayRef prefArray;
74 CFURLRef prefURL;
75 LSLaunchURLSpec prefSpec;
76 OSStatus status;
77
78 prefURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
79 CFSTR(NETWORK_PREF_APP),
80 kCFURLPOSIXPathStyle,
81 FALSE);
82 prefArray = CFArrayCreate(NULL, (const void **)&prefURL, 1, &kCFTypeArrayCallBacks);
83 CFRelease(prefURL);
84
85 status = AECreateDesc('ptru',
86 (const void *)NETWORK_PREF_CMD,
87 strlen(NETWORK_PREF_CMD),
88 &aeDesc);
89 if (status != noErr) {
90 SCLog(TRUE, LOG_ERR, CFSTR("SCMonitor: AECreateDesc() failed: %d"), status);
91 }
92
93 prefSpec.appURL = NULL;
94 prefSpec.itemURLs = prefArray;
95 prefSpec.passThruParams = &aeDesc;
96 prefSpec.launchFlags = kLSLaunchAsync | kLSLaunchDontAddToRecents;
97 prefSpec.asyncRefCon = NULL;
98
99 status = LSOpenFromURLSpec(&prefSpec, NULL);
100 if (status != noErr) {
101 SCLog(TRUE, LOG_ERR, CFSTR("SCMonitor: LSOpenFromURLSpec() failed: %d"), status);
102 }
103
104 CFRelease(prefArray);
105 if (aeDesc.descriptorType != typeNull) AEDisposeDesc(&aeDesc);
106 return;
107 }
108
109
110 static void
111 notify_remove(MyType *myInstance, Boolean cancel)
112 {
113 if (myInstance->userInterfaces != NULL) {
114 CFRelease(myInstance->userInterfaces);
115 myInstance->userInterfaces = NULL;
116 }
117
118 if (myInstance->userRls != NULL) {
119 CFRunLoopSourceInvalidate(myInstance->userRls);
120 CFRelease(myInstance->userRls);
121 myInstance->userRls = NULL;
122 }
123
124 if (myInstance->userNotification != NULL) {
125 if (cancel) {
126 SInt32 status;
127
128 status = CFUserNotificationCancel(myInstance->userNotification);
129 if (status != 0) {
130 SCLog(TRUE, LOG_ERR,
131 CFSTR("SCMonitor: CFUserNotificationCancel() failed, status=%d"),
132 status);
133 }
134 }
135 CFRelease(myInstance->userNotification);
136 myInstance->userNotification = NULL;
137 }
138
139 return;
140 }
141
142
143 static void
144 notify_reply(CFUserNotificationRef userNotification, CFOptionFlags response_flags)
145 {
146 MyType *myInstance = NULL;
147
148 // get instance for notification
149 if (notify_to_instance != NULL) {
150 myInstance = (MyType *)CFDictionaryGetValue(notify_to_instance, userNotification);
151 if (myInstance != NULL) {
152 CFDictionaryRemoveValue(notify_to_instance, userNotification);
153 if (CFDictionaryGetCount(notify_to_instance) == 0) {
154 CFRelease(notify_to_instance);
155 notify_to_instance = NULL;
156 }
157 }
158 }
159 if (myInstance == NULL) {
160 SCLog(TRUE, LOG_ERR, CFSTR("SCMonitor: can't find user notification"));
161 return;
162 }
163
164 // process response
165 switch (response_flags & 0x3) {
166 case kCFUserNotificationDefaultResponse:
167 // user asked to configure interface
168 open_NetworkPrefPane();
169 break;
170 default:
171 // user cancelled
172 break;
173 }
174
175 notify_remove(myInstance, FALSE);
176 return;
177 }
178
179
180 static void
181 notify_add(MyType *myInstance)
182 {
183 CFBundleRef bundle;
184 CFMutableDictionaryRef dict = NULL;
185 SInt32 error = 0;
186 CFIndex i;
187 CFMutableArrayRef message;
188 CFIndex n = CFArrayGetCount(myInstance->userInterfaces);
189 CFURLRef url = NULL;
190
191 if (myInstance->userNotification != NULL) {
192 CFMutableArrayRef save = NULL;
193
194 if (n > 0) {
195 CFRetain(myInstance->userInterfaces);
196 save = myInstance->userInterfaces;
197 }
198 notify_remove(myInstance, TRUE);
199 myInstance->userInterfaces = save;
200 if (n == 0) {
201 return;
202 }
203 }
204
205 dict = CFDictionaryCreateMutable(NULL,
206 0,
207 &kCFTypeDictionaryKeyCallBacks,
208 &kCFTypeDictionaryValueCallBacks);
209
210 // set localization URL
211 bundle = CFBundleGetBundleWithIdentifier(MY_BUNDLE_ID);
212 if (bundle != NULL) {
213 url = CFBundleCopyBundleURL(bundle);
214 }
215 if (url != NULL) {
216 // set URL
217 CFDictionarySetValue(dict, kCFUserNotificationLocalizationURLKey, url);
218 CFRelease(url);
219 } else {
220 SCLog(TRUE, LOG_NOTICE, CFSTR("SCMonitor: can't find bundle"));
221 goto done;
222 }
223
224 // set icon URL
225 url = CFURLCreateFromFileSystemRepresentation(NULL,
226 (const UInt8 *)MY_ICON_PATH,
227 strlen(MY_ICON_PATH),
228 FALSE);
229 if (url != NULL) {
230 CFDictionarySetValue(dict, kCFUserNotificationIconURLKey, url);
231 CFRelease(url);
232 }
233
234 // header
235 CFDictionarySetValue(dict,
236 kCFUserNotificationAlertHeaderKey,
237 (n == 1) ? CFSTR("HEADER_1") : CFSTR("HEADER_N"));
238
239 // message
240 message = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
241 CFArrayAppendValue(message,
242 (n == 1) ? CFSTR("MESSAGE_S1") : CFSTR("MESSAGE_SN"));
243 for (i = 0; i < n; i++) {
244 SCNetworkInterfaceRef interface;
245 CFStringRef name;
246
247 interface = CFArrayGetValueAtIndex(myInstance->userInterfaces, i);
248 name = SCNetworkInterfaceGetLocalizedDisplayName(interface);
249 if (n == 1) {
250 CFArrayAppendValue(message, name);
251 } else {
252 CFStringRef str;
253
254 str = CFStringCreateWithFormat(NULL, NULL, CFSTR("\r\t%@"), name);
255 CFArrayAppendValue(message, str);
256 CFRelease(str);
257 }
258 }
259 CFArrayAppendValue(message,
260 (n == 1) ? CFSTR("MESSAGE_E1") : CFSTR("MESSAGE_EN"));
261 CFDictionarySetValue(dict, kCFUserNotificationAlertMessageKey, message);
262 CFRelease(message);
263
264 // button titles
265 CFDictionaryAddValue(dict, kCFUserNotificationDefaultButtonTitleKey, CFSTR("OPEN_NP"));
266 CFDictionaryAddValue(dict, kCFUserNotificationAlternateButtonTitleKey, CFSTR("CANCEL"));
267
268 // create and post notification
269 myInstance->userNotification = CFUserNotificationCreate(NULL,
270 0,
271 kCFUserNotificationNoteAlertLevel,
272 &error,
273 dict);
274 if (myInstance->userNotification == NULL) {
275 SCLog(TRUE, LOG_ERR, CFSTR("SCMonitor: CFUserNotificationCreate() failed, %d"), error);
276 goto done;
277 }
278
279 // establish callback
280 myInstance->userRls = CFUserNotificationCreateRunLoopSource(NULL,
281 myInstance->userNotification,
282 notify_reply,
283 0);
284 if (myInstance->userRls == NULL) {
285 SCLog(TRUE, LOG_ERR, CFSTR("SCMonitor: CFUserNotificationCreateRunLoopSource() failed"));
286 CFRelease(myInstance->userNotification);
287 myInstance->userNotification = NULL;
288 goto done;
289 }
290 CFRunLoopAddSource(CFRunLoopGetCurrent(), myInstance->userRls, kCFRunLoopDefaultMode);
291
292 // add instance for notification
293 if (notify_to_instance == NULL) {
294 notify_to_instance = CFDictionaryCreateMutable(NULL,
295 0,
296 &kCFTypeDictionaryKeyCallBacks,
297 NULL); // no retain/release/... for values
298 }
299 CFDictionarySetValue(notify_to_instance, myInstance->userNotification, myInstance);
300
301 done :
302
303 if (dict != NULL) CFRelease(dict);
304 return;
305 }
306
307
308 static void
309 notify_configure(MyType *myInstance)
310 {
311 AuthorizationRef authorization = NULL;
312 CFIndex i;
313 CFIndex n;
314 Boolean ok;
315 SCPreferencesRef prefs = NULL;
316 SCNetworkSetRef set = NULL;
317
318 if (geteuid() == 0) {
319 prefs = SCPreferencesCreate(NULL, CFSTR("SCMonitor"), NULL);
320 } else {
321 AuthorizationFlags flags = kAuthorizationFlagDefaults;
322 OSStatus status;
323
324 status = AuthorizationCreate(NULL,
325 kAuthorizationEmptyEnvironment,
326 flags,
327 &authorization);
328 if (status != errAuthorizationSuccess) {
329 SCLog(TRUE, LOG_ERR,
330 CFSTR("AuthorizationCreate() failed: status = %d\n"),
331 status);
332 return;
333 }
334
335 prefs = SCPreferencesCreateWithAuthorization(NULL, CFSTR("SCMonitor"), NULL, authorization);
336 }
337
338 set = SCNetworkSetCopyCurrent(prefs);
339 if (set == NULL) {
340 set = SCNetworkSetCreate(prefs);
341 if (set == NULL) {
342 goto done;
343 }
344 }
345
346 n = CFArrayGetCount(myInstance->userInterfaces);
347 for (i = 0; i < n; i++) {
348 SCNetworkInterfaceRef interface;
349
350 interface = CFArrayGetValueAtIndex(myInstance->userInterfaces, i);
351 ok = SCNetworkSetEstablishDefaultInterfaceConfiguration(set, interface);
352 if (ok) {
353 CFStringRef name;
354
355 name = SCNetworkInterfaceGetLocalizedDisplayName(interface);
356 SCLog(TRUE, LOG_NOTICE, CFSTR("add service for %@"), name);
357 }
358 }
359
360 ok = SCPreferencesCommitChanges(prefs);
361 if (!ok) {
362 SCLog(TRUE, LOG_ERR,
363 CFSTR("SCPreferencesCommitChanges() failed: %s\n"),
364 SCErrorString(SCError()));
365 goto done;
366 }
367
368 ok = SCPreferencesApplyChanges(prefs);
369 if (!ok) {
370 SCLog(TRUE, LOG_ERR,
371 CFSTR("SCPreferencesApplyChanges() failed: %s\n"),
372 SCErrorString(SCError()));
373 goto done;
374 }
375
376 done :
377
378 if (set != NULL) {
379 CFRelease(set);
380 set = NULL;
381 }
382
383 if (prefs != NULL) {
384 CFRelease(prefs);
385 prefs = NULL;
386 }
387
388 if (authorization != NULL) {
389 AuthorizationFree(authorization, kAuthorizationFlagDefaults);
390 // AuthorizationFree(authorization, kAuthorizationFlagDestroyRights);
391 authorization = NULL;
392 }
393
394 CFRelease(myInstance->userInterfaces);
395 myInstance->userInterfaces = NULL;
396
397 return;
398 }
399
400
401 static void
402 updateInterfaceList(SCDynamicStoreRef store, CFArrayRef changes, void * arg)
403 {
404 CFIndex i;
405 CFArrayRef interfaces;
406 MyType *myInstance = (MyType *)arg;
407 CFIndex n;
408 SCPreferencesRef prefs;
409 CFMutableSetRef previouslyKnown = NULL;
410 SCNetworkSetRef set = NULL;
411
412 prefs = SCPreferencesCreate(NULL, CFSTR("SCMonitor"), NULL);
413 if (prefs == NULL) {
414 return;
415 }
416
417 set = SCNetworkSetCopyCurrent(prefs);
418 if (set == NULL) {
419 set = SCNetworkSetCreate(prefs);
420 if (set == NULL) {
421 goto done;
422 }
423 }
424
425 previouslyKnown = CFSetCreateMutableCopy(NULL, 0, myInstance->knownInterfaces);
426
427 interfaces = SCNetworkInterfaceCopyAll();
428 if (interfaces != NULL) {
429
430 n = CFArrayGetCount(interfaces);
431 for (i = 0; i < n; i++) {
432 CFStringRef bsdName;
433 SCNetworkInterfaceRef interface;
434 Boolean ok;
435
436 interface = CFArrayGetValueAtIndex(interfaces, i);
437 bsdName = SCNetworkInterfaceGetBSDName(interface);
438 if (bsdName == NULL) {
439 // if no BSD name
440 continue;
441 }
442
443 CFSetRemoveValue(previouslyKnown, bsdName);
444
445 if (CFSetContainsValue(myInstance->knownInterfaces, bsdName)) {
446 // if known interface
447 continue;
448 }
449
450 CFSetAddValue(myInstance->knownInterfaces, bsdName);
451
452 ok = SCNetworkSetEstablishDefaultInterfaceConfiguration(set, interface);
453 if (ok) {
454 // this is a *new* interface
455 if (myInstance->userInterfaces == NULL) {
456 myInstance->userInterfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
457 }
458 CFArrayAppendValue(myInstance->userInterfaces, interface);
459 }
460 }
461
462 CFRelease(interfaces);
463 }
464
465 n = CFSetGetCount(previouslyKnown);
466 if (n > 0) {
467 const void * names_q[32];
468 const void ** names = names_q;
469
470 if (n > (CFIndex)(sizeof(names_q) / sizeof(CFTypeRef)))
471 names = CFAllocatorAllocate(NULL, n * sizeof(CFTypeRef), 0);
472 CFSetGetValues(previouslyKnown, names);
473 for (i = 0; i < n; i++) {
474 if (myInstance->userInterfaces != NULL) {
475 CFIndex j;
476
477 j = CFArrayGetCount(myInstance->userInterfaces);
478 while (--j >= 0) {
479 CFStringRef bsdName;
480 SCNetworkInterfaceRef interface;
481
482 interface = CFArrayGetValueAtIndex(myInstance->userInterfaces, j);
483 bsdName = SCNetworkInterfaceGetBSDName(interface);
484 if (CFEqual(bsdName, names[i])) {
485 // if we have previously posted a notification
486 // for this no-longer-present interface
487 CFArrayRemoveValueAtIndex(myInstance->userInterfaces, j);
488 }
489 }
490 }
491
492 CFSetRemoveValue(myInstance->knownInterfaces, names[i]);
493 }
494 if (names != names_q) CFAllocatorDeallocate(NULL, names);
495 }
496
497 done :
498
499 if (myInstance->userInterfaces != NULL) {
500 if (myInstance->no_user_intervention) {
501 // add network services for new interfaces
502 notify_configure(myInstance);
503 } else {
504 // post notification
505 notify_add(myInstance);
506 }
507 }
508
509 if (set != NULL) CFRelease(set);
510 CFRelease(prefs);
511 return;
512 }
513
514
515 static void
516 watcher_remove(MyType *myInstance)
517 {
518 if (myInstance->monitorRls != NULL) {
519 CFRunLoopSourceInvalidate(myInstance->monitorRls);
520 CFRelease(myInstance->monitorRls);
521 myInstance->monitorRls = NULL;
522 }
523
524 if (myInstance->knownInterfaces != NULL) {
525 CFRelease(myInstance->knownInterfaces);
526 myInstance->knownInterfaces = NULL;
527 }
528
529 return;
530 }
531
532
533 static void
534 watcher_add(MyType *myInstance)
535 {
536 CFBundleRef bundle;
537 SCDynamicStoreContext context = { 0, (void *)myInstance, NULL, NULL, NULL };
538 CFDictionaryRef dict;
539 CFStringRef key;
540 CFArrayRef keys;
541 SCDynamicStoreRef store;
542
543 bundle = CFBundleGetBundleWithIdentifier(MY_BUNDLE_ID);
544 if (bundle != NULL) {
545 CFDictionaryRef info;
546 CFBooleanRef user_intervention;
547
548 info = CFBundleGetInfoDictionary(bundle);
549 user_intervention = CFDictionaryGetValue(info, CFSTR("User Intervention"));
550 if (isA_CFBoolean(user_intervention)) {
551 myInstance->no_user_intervention = !CFBooleanGetValue(user_intervention);
552 }
553 }
554
555 store = SCDynamicStoreCreate(NULL, CFSTR("SCMonitor"), updateInterfaceList, &context);
556 if (store == NULL) {
557 SCLog(TRUE, LOG_ERR,
558 CFSTR("SCMonitor: SCDynamicStoreCreate() failed: %s"),
559 SCErrorString(SCError()));
560 return;
561 }
562
563 key = SCDynamicStoreKeyCreateNetworkInterface(NULL, kSCDynamicStoreDomainState);
564
565 // watch for changes to the list of network interfaces
566 keys = CFArrayCreate(NULL, (const void **)&key, 1, &kCFTypeArrayCallBacks);
567 SCDynamicStoreSetNotificationKeys(store, NULL, keys);
568 CFRelease(keys);
569 myInstance->monitorRls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
570 CFRunLoopAddSource(CFRunLoopGetCurrent(),
571 myInstance->monitorRls,
572 kCFRunLoopDefaultMode);
573
574 // initialize the list of known interfaces
575 myInstance->knownInterfaces = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
576 dict = SCDynamicStoreCopyValue(store, key);
577 if (dict != NULL) {
578 if (isA_CFDictionary(dict)) {
579 CFIndex i;
580 CFArrayRef interfaces;
581 CFIndex n;
582
583 interfaces = CFDictionaryGetValue(dict, kSCPropNetInterfaces);
584 n = isA_CFArray(interfaces) ? CFArrayGetCount(interfaces) : 0;
585 for (i = 0; i < n; i++) {
586 CFStringRef bsdName;
587
588 bsdName = CFArrayGetValueAtIndex(interfaces, i);
589 if (isA_CFString(bsdName)) {
590 CFSetAddValue(myInstance->knownInterfaces, bsdName);
591 }
592 }
593 }
594
595 CFRelease(dict);
596 }
597
598 CFRelease(key);
599 CFRelease(store);
600 return;
601 }
602
603
604 #pragma mark -
605 #pragma mark UserEventAgent stubs
606
607
608 static HRESULT
609 myQueryInterface(void *myInstance, REFIID iid, LPVOID *ppv)
610 {
611 CFUUIDRef interfaceID = CFUUIDCreateFromUUIDBytes(NULL, iid);
612
613 // Test the requested ID against the valid interfaces.
614 if (CFEqual(interfaceID, kUserEventAgentInterfaceID)) {
615 ((MyType *) myInstance)->_UserEventAgentInterface->AddRef(myInstance);
616 *ppv = myInstance;
617 CFRelease(interfaceID);
618 return S_OK;
619 }
620
621 if (CFEqual(interfaceID, IUnknownUUID)) {
622 ((MyType *) myInstance)->_UserEventAgentInterface->AddRef(myInstance);
623 *ppv = myInstance;
624 CFRelease(interfaceID);
625 return S_OK;
626 }
627
628 // Requested interface unknown, bail with error.
629 *ppv = NULL;
630 CFRelease(interfaceID);
631 return E_NOINTERFACE;
632 }
633
634
635 static ULONG
636 myAddRef(void *myInstance)
637 {
638 ((MyType *) myInstance)->_refCount++;
639 return ((MyType *) myInstance)->_refCount;
640 }
641
642
643 static ULONG
644 myRelease(void *myInstance)
645 {
646 ((MyType *) myInstance)->_refCount--;
647 if (((MyType *) myInstance)->_refCount == 0) {
648 CFUUIDRef factoryID = ((MyType *) myInstance)->_factoryID;
649
650 if (factoryID != NULL) {
651 CFPlugInRemoveInstanceForFactory(factoryID);
652 CFRelease(factoryID);
653
654 watcher_remove((MyType *)myInstance);
655 notify_remove((MyType *)myInstance, TRUE);
656 }
657 free(myInstance);
658 return 0;
659 }
660
661 return ((MyType *) myInstance)->_refCount;
662 }
663
664
665 static void
666 myInstall(void *myInstance)
667 {
668 watcher_add((MyType *)myInstance);
669 return;
670 }
671
672
673 static UserEventAgentInterfaceStruct UserEventAgentInterfaceFtbl = {
674 NULL, // Required padding for COM
675 myQueryInterface, // These three are the required COM functions
676 myAddRef,
677 myRelease,
678 myInstall // Interface implementation
679 };
680
681
682 void *
683 UserEventAgentFactory(CFAllocatorRef allocator, CFUUIDRef typeID)
684 {
685 MyType *newOne = NULL;
686
687 if (CFEqual(typeID, kUserEventAgentTypeID)) {
688 newOne = (MyType *)malloc(sizeof(MyType));
689 bzero(newOne, sizeof(*newOne));
690 newOne->_UserEventAgentInterface = &UserEventAgentInterfaceFtbl;
691 newOne->_factoryID = (CFUUIDRef)CFRetain(kUserEventAgentFactoryID);
692 CFPlugInAddInstanceForFactory(kUserEventAgentFactoryID);
693 newOne->_refCount = 1;
694 }
695
696 return newOne;
697 }
698
699
700 #ifdef MAIN
701 int
702 main(int argc, char **argv)
703 {
704 MyType *newOne = (MyType *)malloc(sizeof(MyType));
705
706 _sc_log = FALSE;
707 _sc_verbose = (argc > 1) ? TRUE : FALSE;
708
709 bzero(newOne, sizeof(*newOne));
710 myInstall(newOne);
711 CFRunLoopRun();
712 exit(0);
713 return (0);
714 }
715 #endif // MAIN