]> git.saurik.com Git - apple/configd.git/blob - Plugins/KernelEventMonitor/eventmon.c
configd-204.tar.gz
[apple/configd.git] / Plugins / KernelEventMonitor / eventmon.c
1 /*
2 * Copyright (c) 2000-2007 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 * December 3, 2002 Dieter Siegmund <dieter@apple.com>
28 * - handle the new KEV_INET_ARPCOLLISION event
29 * - format the event into a DynamicStore key
30 * State:/Network/Interface/ifname/IPv4Collision/ip_addr/hw_addr
31 * and send a notification on the key
32 *
33 * August 8, 2002 Allan Nathanson <ajn@apple.com>
34 * - added support for KEV_INET6_xxx events
35 *
36 * January 6, 2002 Jessica Vazquez <vazquez@apple.com>
37 * - added handling for KEV_ATALK_xxx events
38 *
39 * July 2, 2001 Dieter Siegmund <dieter@apple.com>
40 * - added handling for KEV_DL_PROTO_{ATTACHED, DETACHED}
41 * - mark an interface up if the number of protocols remaining is not 0,
42 * mark an interface down if the number is zero
43 * - allocate socket on demand instead of keeping it open all the time
44 *
45 * June 23, 2001 Allan Nathanson <ajn@apple.com>
46 * - update to public SystemConfiguration.framework APIs
47 *
48 * May 17, 2001 Allan Nathanson <ajn@apple.com>
49 * - add/maintain per-interface address/netmask/destaddr information
50 * in the dynamic store.
51 *
52 * June 30, 2000 Allan Nathanson <ajn@apple.com>
53 * - initial revision
54 */
55
56 #include "eventmon.h"
57 #include "cache.h"
58 #include "ev_dlil.h"
59 #include "ev_ipv4.h"
60 #include "ev_ipv6.h"
61 #include "ev_appletalk.h"
62
63 #include <notify.h>
64
65 static const char *inetEventName[] = {
66 "",
67 "INET address added",
68 "INET address changed",
69 "INET address deleted",
70 "INET destination address changed",
71 "INET broadcast address changed",
72 "INET netmask changed",
73 "INET ARP collision",
74 };
75
76 static const char *dlEventName[] = {
77 "",
78 "KEV_DL_SIFFLAGS",
79 "KEV_DL_SIFMETRICS",
80 "KEV_DL_SIFMTU",
81 "KEV_DL_SIFPHYS",
82 "KEV_DL_SIFMEDIA",
83 "KEV_DL_SIFGENERIC",
84 "KEV_DL_ADDMULTI",
85 "KEV_DL_DELMULTI",
86 "KEV_DL_IF_ATTACHED",
87 "KEV_DL_IF_DETACHING",
88 "KEV_DL_IF_DETACHED",
89 "KEV_DL_LINK_OFF",
90 "KEV_DL_LINK_ON",
91 "KEV_DL_PROTO_ATTACHED",
92 "KEV_DL_PROTO_DETACHED",
93 };
94
95 static const char *atalkEventName[] = {
96 "",
97 "KEV_ATALK_ENABLED",
98 "KEV_ATALK_DISABLED",
99 "KEV_ATALK_ZONEUPDATED",
100 "KEV_ATALK_ROUTERUP",
101 "KEV_ATALK_ROUTERUP_INVALID",
102 "KEV_ATALK_ROUTERDOWN",
103 "KEV_ATALK_ZONELISTCHANGED"
104 };
105
106 static const char *inet6EventName[] = {
107 "",
108 "KEV_INET6_NEW_USER_ADDR",
109 "KEV_INET6_CHANGED_ADDR",
110 "KEV_INET6_ADDR_DELETED",
111 "KEV_INET6_NEW_LL_ADDR",
112 "KEV_INET6_NEW_RTADV_ADDR",
113 "KEV_INET6_DEFROUTER"
114 };
115
116
117 __private_extern__ Boolean network_changed = FALSE;
118 __private_extern__ SCDynamicStoreRef store = NULL;
119 __private_extern__ Boolean _verbose = FALSE;
120
121
122 __private_extern__
123 int
124 dgram_socket(int domain)
125 {
126 return (socket(domain, SOCK_DGRAM, 0));
127 }
128
129 static int
130 ifflags_set(int s, char * name, short flags)
131 {
132 struct ifreq ifr;
133 int ret;
134
135 bzero(&ifr, sizeof(ifr));
136 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
137 ret = ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr);
138 if (ret == -1) {
139 return (ret);
140 }
141 ifr.ifr_flags |= flags;
142 return (ioctl(s, SIOCSIFFLAGS, &ifr));
143 }
144
145 static int
146 ifflags_clear(int s, char * name, short flags)
147 {
148 struct ifreq ifr;
149 int ret;
150
151 bzero(&ifr, sizeof(ifr));
152 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
153 ret = ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr);
154 if (ret == -1) {
155 return (ret);
156 }
157 ifr.ifr_flags &= ~flags;
158 return (ioctl(s, SIOCSIFFLAGS, &ifr));
159 }
160
161 static void
162 mark_if_up(char * name)
163 {
164 int s = dgram_socket(AF_INET);
165 if (s == -1)
166 return;
167 ifflags_set(s, name, IFF_UP);
168 close(s);
169 }
170
171 static void
172 mark_if_down(char * name)
173 {
174 int s = dgram_socket(AF_INET);
175 if (s == -1)
176 return;
177 ifflags_clear(s, name, IFF_UP);
178 close(s);
179 }
180
181 static void
182 post_network_changed(void)
183 {
184 if (network_changed) {
185 uint32_t status;
186
187 status = notify_post("com.apple.system.config.network_change");
188 if (status != NOTIFY_STATUS_OK) {
189 SCLog(TRUE, LOG_ERR, CFSTR("notify_post() failed: error=%ld"), status);
190 }
191
192 network_changed = FALSE;
193 }
194
195 return;
196 }
197
198 static void
199 logEvent(CFStringRef evStr, struct kern_event_msg *ev_msg)
200 {
201 int i;
202 int j;
203
204 SCLog(_verbose, LOG_DEBUG, CFSTR("%@ event:"), evStr);
205 SCLog(_verbose, LOG_DEBUG,
206 CFSTR(" Event size=%d, id=%d, vendor=%d, class=%d, subclass=%d, code=%d"),
207 ev_msg->total_size,
208 ev_msg->id,
209 ev_msg->vendor_code,
210 ev_msg->kev_class,
211 ev_msg->kev_subclass,
212 ev_msg->event_code);
213 for (i = 0, j = KEV_MSG_HEADER_SIZE; j < ev_msg->total_size; i++, j+=4) {
214 SCLog(_verbose, LOG_DEBUG, CFSTR(" Event data[%2d] = %08lx"), i, ev_msg->event_data[i]);
215 }
216 }
217
218 static const char *
219 inetEventNameString(uint32_t event_code)
220 {
221 if (event_code <= KEV_INET_ARPCOLLISION) {
222 return (inetEventName[event_code]);
223 }
224 return ("New Apple network INET subcode");
225 }
226
227 static const char *
228 inet6EventNameString(uint32_t event_code)
229 {
230 if (event_code <= KEV_INET6_DEFROUTER) {
231 return (inet6EventName[event_code]);
232 }
233 return ("New Apple network INET6 subcode");
234 }
235
236 static const char *
237 dlEventNameString(uint32_t event_code)
238 {
239 if (event_code <= KEV_DL_PROTO_DETACHED) {
240 return (dlEventName[event_code]);
241 }
242 return ("New Apple network DL subcode");
243 }
244
245 static const char *
246 atalkEventNameString(uint32_t event_code)
247 {
248 if (event_code <= KEV_ATALK_ZONELISTCHANGED) {
249 return (atalkEventName[event_code]);
250 }
251 return ("New Apple network AppleTalk subcode");
252 }
253
254
255 static void
256 copy_if_name(struct net_event_data * ev, char * ifr_name, int ifr_len)
257 {
258 snprintf(ifr_name, ifr_len, "%s%d", ev->if_name, ev->if_unit);
259 return;
260 }
261
262 static void
263 processEvent_Apple_Network(struct kern_event_msg *ev_msg)
264 {
265 const char * eventName = NULL;
266 int dataLen = (ev_msg->total_size - KEV_MSG_HEADER_SIZE);
267 void * event_data = &ev_msg->event_data[0];
268 Boolean handled = TRUE;
269 char ifr_name[IFNAMSIZ + 1];
270
271 switch (ev_msg->kev_subclass) {
272 case KEV_INET_SUBCLASS : {
273 eventName = inetEventNameString(ev_msg->event_code);
274 switch (ev_msg->event_code) {
275 case KEV_INET_NEW_ADDR :
276 case KEV_INET_CHANGED_ADDR :
277 case KEV_INET_ADDR_DELETED :
278 case KEV_INET_SIFDSTADDR :
279 case KEV_INET_SIFBRDADDR :
280 case KEV_INET_SIFNETMASK : {
281 struct kev_in_data * ev;
282
283 ev = (struct kev_in_data *)event_data;
284 if (dataLen < sizeof(*ev)) {
285 handled = FALSE;
286 break;
287 }
288 copy_if_name(&ev->link_data, ifr_name, sizeof(ifr_name));
289 interface_update_ipv4(NULL, ifr_name);
290 break;
291 }
292 case KEV_INET_ARPCOLLISION : {
293 struct kev_in_collision * ev;
294
295 ev = (struct kev_in_collision *)event_data;
296 if ((dataLen < sizeof(*ev))
297 || (dataLen < (sizeof(*ev) + ev->hw_len))) {
298 handled = FALSE;
299 break;
300 }
301 copy_if_name(&ev->link_data, ifr_name, sizeof(ifr_name));
302 interface_collision_ipv4(ifr_name,
303 ev->ia_ipaddr,
304 ev->hw_len,
305 ev->hw_addr);
306 break;
307 }
308 case KEV_INET_PORTINUSE : {
309 struct kev_in_portinuse * ev;
310 ev = (struct kev_in_portinuse *)event_data;
311 if (dataLen < sizeof(*ev)) {
312 handled = FALSE;
313 break;
314 }
315 port_in_use_ipv4(ev->port, ev->req_pid);
316 break;
317 }
318 default :
319 handled = FALSE;
320 break;
321 }
322 break;
323 }
324 case KEV_INET6_SUBCLASS : {
325 struct kev_in6_data * ev;
326
327 eventName = inet6EventNameString(ev_msg->event_code);
328 ev = (struct kev_in6_data *)event_data;
329 switch (ev_msg->event_code) {
330 case KEV_INET6_NEW_USER_ADDR :
331 case KEV_INET6_CHANGED_ADDR :
332 case KEV_INET6_ADDR_DELETED :
333 case KEV_INET6_NEW_LL_ADDR :
334 case KEV_INET6_NEW_RTADV_ADDR :
335 case KEV_INET6_DEFROUTER :
336 if (dataLen < sizeof(*ev)) {
337 handled = FALSE;
338 break;
339 }
340 copy_if_name(&ev->link_data, ifr_name, sizeof(ifr_name));
341 interface_update_ipv6(NULL, ifr_name);
342 break;
343
344 default :
345 handled = FALSE;
346 break;
347 }
348 break;
349 }
350 case KEV_DL_SUBCLASS : {
351 struct net_event_data * ev;
352
353 eventName = dlEventNameString(ev_msg->event_code);
354 ev = (struct net_event_data *)event_data;
355 switch (ev_msg->event_code) {
356 case KEV_DL_IF_ATTACHED :
357 /*
358 * new interface added
359 */
360 if (dataLen < sizeof(*ev)) {
361 handled = FALSE;
362 break;
363 }
364 copy_if_name(ev, ifr_name, sizeof(ifr_name));
365 link_add(ifr_name);
366 break;
367
368 case KEV_DL_IF_DETACHED :
369 /*
370 * interface removed
371 */
372 if (dataLen < sizeof(*ev)) {
373 handled = FALSE;
374 break;
375 }
376 copy_if_name(ev, ifr_name, sizeof(ifr_name));
377 link_remove(ifr_name);
378 break;
379
380 case KEV_DL_IF_DETACHING :
381 /*
382 * interface detaching
383 */
384 if (dataLen < sizeof(*ev)) {
385 handled = FALSE;
386 break;
387 }
388 copy_if_name(ev, ifr_name, sizeof(ifr_name));
389 interface_detaching(ifr_name);
390 break;
391
392 case KEV_DL_SIFFLAGS :
393 case KEV_DL_SIFMETRICS :
394 case KEV_DL_SIFMTU :
395 case KEV_DL_SIFPHYS :
396 case KEV_DL_SIFMEDIA :
397 case KEV_DL_SIFGENERIC :
398 case KEV_DL_ADDMULTI :
399 case KEV_DL_DELMULTI :
400 handled = FALSE;
401 break;
402
403 case KEV_DL_PROTO_ATTACHED :
404 case KEV_DL_PROTO_DETACHED : {
405 struct kev_dl_proto_data * protoEvent;
406
407 protoEvent = (struct kev_dl_proto_data *)event_data;
408 if (dataLen < sizeof(*protoEvent)) {
409 handled = FALSE;
410 break;
411 }
412 copy_if_name(&protoEvent->link_data,
413 ifr_name, sizeof(ifr_name));
414 if (protoEvent->proto_remaining_count == 0) {
415 mark_if_down(ifr_name);
416 } else {
417 mark_if_up(ifr_name);
418 }
419 break;
420 }
421
422 case KEV_DL_LINK_OFF :
423 case KEV_DL_LINK_ON :
424 /*
425 * update the link status in the store
426 */
427 if (dataLen < sizeof(*ev)) {
428 handled = FALSE;
429 break;
430 }
431 copy_if_name(ev, ifr_name, sizeof(ifr_name));
432 link_update_status(ifr_name, FALSE);
433 break;
434
435 default :
436 handled = FALSE;
437 break;
438 }
439 break;
440 }
441 case KEV_ATALK_SUBCLASS: {
442 struct kev_atalk_data * ev;
443
444 eventName = atalkEventNameString(ev_msg->event_code);
445 ev = (struct kev_atalk_data *)event_data;
446 if (dataLen < sizeof(*ev)) {
447 handled = FALSE;
448 break;
449 }
450 copy_if_name(&ev->link_data, ifr_name, sizeof(ifr_name));
451 switch (ev_msg->event_code) {
452 case KEV_ATALK_ENABLED:
453 interface_update_atalk_address(ev, ifr_name);
454 break;
455
456 case KEV_ATALK_DISABLED:
457 interface_update_shutdown_atalk();
458 break;
459
460 case KEV_ATALK_ZONEUPDATED:
461 interface_update_atalk_zone(ev, ifr_name);
462 break;
463
464 case KEV_ATALK_ROUTERUP:
465 case KEV_ATALK_ROUTERUP_INVALID:
466 case KEV_ATALK_ROUTERDOWN:
467 interface_update_appletalk(NULL, ifr_name);
468 break;
469
470 case KEV_ATALK_ZONELISTCHANGED:
471 break;
472
473 default :
474 handled = FALSE;
475 break;
476 }
477 break;
478 }
479 default :
480 handled = FALSE;
481 break;
482 }
483
484 if (handled == FALSE) {
485 CFStringRef evStr;
486
487 evStr = CFStringCreateWithCString(NULL,
488 (eventName != NULL) ? eventName : "New Apple network subclass",
489 kCFStringEncodingASCII);
490 logEvent(evStr, ev_msg);
491 CFRelease(evStr);
492 }
493 return;
494 }
495
496
497 static void
498 processEvent_Apple_IOKit(struct kern_event_msg *ev_msg)
499 {
500 switch (ev_msg->kev_subclass) {
501 default :
502 logEvent(CFSTR("New Apple IOKit subclass"), ev_msg);
503 break;
504 }
505
506 return;
507 }
508
509
510 static void
511 eventCallback(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info)
512 {
513 int so = CFSocketGetNative(s);
514 int status;
515 char buf[1024];
516 struct kern_event_msg *ev_msg = (struct kern_event_msg *)&buf[0];
517 int offset = 0;
518
519 status = recv(so, &buf, sizeof(buf), 0);
520 if (status == -1) {
521 SCLog(TRUE, LOG_ERR, CFSTR("recv() failed: %s"), strerror(errno));
522 goto error;
523 }
524
525 cache_open();
526
527 while (offset < status) {
528 if ((offset + ev_msg->total_size) > status) {
529 SCLog(TRUE, LOG_NOTICE, CFSTR("missed SYSPROTO_EVENT event, buffer not big enough"));
530 break;
531 }
532
533 switch (ev_msg->vendor_code) {
534 case KEV_VENDOR_APPLE :
535 switch (ev_msg->kev_class) {
536 case KEV_NETWORK_CLASS :
537 processEvent_Apple_Network(ev_msg);
538 break;
539 case KEV_IOKIT_CLASS :
540 processEvent_Apple_IOKit(ev_msg);
541 break;
542 default :
543 /* unrecognized (Apple) event class */
544 logEvent(CFSTR("New (Apple) class"), ev_msg);
545 break;
546 }
547 break;
548 default :
549 /* unrecognized vendor code */
550 logEvent(CFSTR("New vendor"), ev_msg);
551 break;
552 }
553 offset += ev_msg->total_size;
554 ev_msg = (struct kern_event_msg *)&buf[offset];
555 }
556
557 cache_write(store);
558 cache_close();
559 post_network_changed();
560
561 return;
562
563 error :
564
565 SCLog(TRUE, LOG_ERR, CFSTR("kernel event monitor disabled."));
566 CFSocketInvalidate(s);
567 return;
568
569 }
570
571
572 __private_extern__
573 void
574 prime_KernelEventMonitor()
575 {
576 struct ifaddrs *ifap = NULL;
577 struct ifaddrs *scan;
578 int sock = -1;
579
580 SCLog(_verbose, LOG_DEBUG, CFSTR("prime() called"));
581
582 cache_open();
583
584 sock = dgram_socket(AF_INET);
585 if (sock == -1) {
586 SCLog(TRUE, LOG_ERR, CFSTR("could not get interface list, socket() failed: %s"), strerror(errno));
587 goto done;
588 }
589
590 if (getifaddrs(&ifap) == -1) {
591 SCLog(TRUE,
592 LOG_ERR,
593 CFSTR("could not get interface info, getifaddrs() failed: %s"),
594 strerror(errno));
595 goto done;
596 }
597
598 /* update list of interfaces & link status */
599 for (scan = ifap; scan != NULL; scan = scan->ifa_next) {
600 if (scan->ifa_addr == NULL
601 || scan->ifa_addr->sa_family != AF_LINK) {
602 continue;
603 }
604 /* get the per-interface link/media information */
605 link_add(scan->ifa_name);
606 }
607
608 /*
609 * update IPv4 network addresses already assigned to
610 * the interfaces.
611 */
612 interface_update_ipv4(ifap, NULL);
613
614 /*
615 * update IPv6 network addresses already assigned to
616 * the interfaces.
617 */
618 interface_update_ipv6(ifap, NULL);
619
620 /*
621 * update AppleTalk network addresses already assigned
622 * to the interfaces.
623 */
624 interface_update_appletalk(ifap, NULL);
625
626 freeifaddrs(ifap);
627
628 done:
629 if (sock != -1)
630 close(sock);
631
632 cache_write(store);
633 cache_close();
634
635 network_changed = TRUE;
636 post_network_changed();
637
638 return;
639 }
640
641
642 static CFStringRef
643 kevSocketCopyDescription(const void *info)
644 {
645 return CFStringCreateWithFormat(NULL, NULL, CFSTR("<kernel event socket>"));
646 }
647
648
649 __private_extern__
650 void
651 load_KernelEventMonitor(CFBundleRef bundle, Boolean bundleVerbose)
652 {
653 int so;
654 int status;
655 struct kev_request kev_req;
656 CFSocketRef es;
657 CFSocketContext context = { 0
658 , (void *)1
659 , NULL
660 , NULL
661 , kevSocketCopyDescription
662 };
663 CFRunLoopSourceRef rls;
664
665 if (bundleVerbose) {
666 _verbose = TRUE;
667 }
668
669 SCLog(_verbose, LOG_DEBUG, CFSTR("load() called"));
670 SCLog(_verbose, LOG_DEBUG, CFSTR(" bundle ID = %@"), CFBundleGetIdentifier(bundle));
671
672 /* open a "configd" session to allow cache updates */
673 store = SCDynamicStoreCreate(NULL,
674 CFSTR("Kernel Event Monitor plug-in"),
675 NULL,
676 NULL);
677 if (store == NULL) {
678 SCLog(TRUE, LOG_ERR, CFSTR("SCDnamicStoreCreate() failed: %s"), SCErrorString(SCError()));
679 SCLog(TRUE, LOG_ERR, CFSTR("kernel event monitor disabled."));
680 return;
681 }
682
683 /* Open an event socket */
684 so = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT);
685 if (so != -1) {
686 /* establish filter to return all events */
687 kev_req.vendor_code = 0;
688 kev_req.kev_class = 0; /* Not used if vendor_code is 0 */
689 kev_req.kev_subclass = 0; /* Not used if either kev_class OR vendor_code are 0 */
690 status = ioctl(so, SIOCSKEVFILT, &kev_req);
691 if (status) {
692 SCLog(TRUE, LOG_ERR, CFSTR("could not establish event filter, ioctl() failed: %s"), strerror(errno));
693 (void) close(so);
694 so = -1;
695 }
696 } else {
697 SCLog(TRUE, LOG_ERR, CFSTR("could not open event socket, socket() failed: %s"), strerror(errno));
698 }
699
700 if (so != -1) {
701 int yes = 1;
702
703 status = ioctl(so, FIONBIO, &yes);
704 if (status) {
705 SCLog(TRUE, LOG_ERR, CFSTR("could not set non-blocking io, ioctl() failed: %s"), strerror(errno));
706 (void) close(so);
707 so = -1;
708 }
709 }
710
711 if (so == -1) {
712 SCLog(TRUE, LOG_ERR, CFSTR("kernel event monitor disabled."));
713 CFRelease(store);
714 return;
715 }
716
717 /* Create a CFSocketRef for the PF_SYSTEM kernel event socket */
718 es = CFSocketCreateWithNative(NULL,
719 so,
720 kCFSocketReadCallBack,
721 eventCallback,
722 &context);
723
724 /* Create and add a run loop source for the event socket */
725 rls = CFSocketCreateRunLoopSource(NULL, es, 0);
726 CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
727 CFRelease(rls);
728 CFRelease(es);
729
730 return;
731 }
732
733 #ifdef MAIN
734
735 #include "ev_dlil.c"
736
737 #define appendAddress appendAddress_v4
738 #define getIF getIF_v4
739 #define updateStore updateStore_v4
740 #include "ev_ipv4.c"
741 #undef appendAddress
742 #undef getIF
743 #undef updateStore
744
745 #define appendAddress appendAddress_v6
746 #define getIF getIF_v6
747 #define updateStore updateStore_v6
748 #include "ev_ipv6.c"
749 #undef appendAddress
750 #undef getIF
751 #undef updateStore
752
753 #define getIF getIF_at
754 #define updateStore updateStore_at
755 #include "ev_appletalk.c"
756 #undef getIF
757 #undef updateStore
758
759 int
760 main(int argc, char **argv)
761 {
762 _sc_log = FALSE;
763 _sc_verbose = (argc > 1) ? TRUE : FALSE;
764
765 load_KernelEventMonitor(CFBundleGetMainBundle(), (argc > 1) ? TRUE : FALSE);
766 prime_KernelEventMonitor();
767 CFRunLoopRun();
768 /* not reached */
769 exit(0);
770 return 0;
771 }
772 #endif