]> git.saurik.com Git - apple/configd.git/blobdiff - Plugins/KernelEventMonitor/eventmon.c
configd-130.tar.gz
[apple/configd.git] / Plugins / KernelEventMonitor / eventmon.c
diff --git a/Plugins/KernelEventMonitor/eventmon.c b/Plugins/KernelEventMonitor/eventmon.c
new file mode 100644 (file)
index 0000000..24946f3
--- /dev/null
@@ -0,0 +1,727 @@
+/*
+ * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Modification History
+ *
+ * December 3, 2002            Dieter Siegmund <dieter@apple.com>
+ * - handle the new KEV_INET_ARPCOLLISION event
+ * - format the event into a DynamicStore key
+ *     State:/Network/Interface/ifname/IPv4Collision/ip_addr/hw_addr
+ *   and send a notification on the key
+ *
+ * August 8, 2002              Allan Nathanson <ajn@apple.com>
+ * - added support for KEV_INET6_xxx events
+ *
+ * January 6, 2002             Jessica Vazquez <vazquez@apple.com>
+ * - added handling for KEV_ATALK_xxx events
+ *
+ * July 2, 2001                        Dieter Siegmund <dieter@apple.com>
+ * - added handling for KEV_DL_PROTO_{ATTACHED, DETACHED}
+ * - mark an interface up if the number of protocols remaining is not 0,
+ *   mark an interface down if the number is zero
+ * - allocate socket on demand instead of keeping it open all the time
+ *
+ * June 23, 2001               Allan Nathanson <ajn@apple.com>
+ * - update to public SystemConfiguration.framework APIs
+ *
+ * May 17, 2001                        Allan Nathanson <ajn@apple.com>
+ * - add/maintain per-interface address/netmask/destaddr information
+ *   in the dynamic store.
+ *
+ * June 30, 2000               Allan Nathanson <ajn@apple.com>
+ * - initial revision
+ */
+
+#include "eventmon.h"
+#include "cache.h"
+#include "ev_dlil.h"
+#include "ev_ipv4.h"
+#include "ev_ipv6.h"
+#include "ev_appletalk.h"
+
+static const char *inetEventName[] = {
+       "",
+       "INET address added",
+       "INET address changed",
+       "INET address deleted",
+       "INET destination address changed",
+       "INET broadcast address changed",
+       "INET netmask changed",
+       "INET ARP collision",
+};
+
+static const char *dlEventName[] = {
+       "",
+       "KEV_DL_SIFFLAGS",
+       "KEV_DL_SIFMETRICS",
+       "KEV_DL_SIFMTU",
+       "KEV_DL_SIFPHYS",
+       "KEV_DL_SIFMEDIA",
+       "KEV_DL_SIFGENERIC",
+       "KEV_DL_ADDMULTI",
+       "KEV_DL_DELMULTI",
+       "KEV_DL_IF_ATTACHED",
+       "KEV_DL_IF_DETACHING",
+       "KEV_DL_IF_DETACHED",
+       "KEV_DL_LINK_OFF",
+       "KEV_DL_LINK_ON",
+       "KEV_DL_PROTO_ATTACHED",
+       "KEV_DL_PROTO_DETACHED",
+};
+
+static const char *atalkEventName[] = {
+       "",
+       "KEV_ATALK_ENABLED",
+       "KEV_ATALK_DISABLED",
+       "KEV_ATALK_ZONEUPDATED",
+       "KEV_ATALK_ROUTERUP",
+       "KEV_ATALK_ROUTERUP_INVALID",
+       "KEV_ATALK_ROUTERDOWN",
+       "KEV_ATALK_ZONELISTCHANGED"
+};
+
+static const char *inet6EventName[] = {
+       "",
+       "KEV_INET6_NEW_USER_ADDR",
+       "KEV_INET6_CHANGED_ADDR",
+       "KEV_INET6_ADDR_DELETED",
+       "KEV_INET6_NEW_LL_ADDR",
+       "KEV_INET6_NEW_RTADV_ADDR",
+       "KEV_INET6_DEFROUTER"
+
+};
+
+
+__private_extern__ SCDynamicStoreRef   store           = NULL;
+__private_extern__ Boolean             _verbose        = FALSE;
+
+
+__private_extern__
+int
+dgram_socket(int domain)
+{
+    return (socket(domain, SOCK_DGRAM, 0));
+}
+
+static int
+ifflags_set(int s, char * name, short flags)
+{
+    struct ifreq       ifr;
+    int                ret;
+
+    bzero(&ifr, sizeof(ifr));
+    strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+    ret = ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr);
+    if (ret < 0) {
+               return (ret);
+    }
+    ifr.ifr_flags |= flags;
+    return (ioctl(s, SIOCSIFFLAGS, &ifr));
+}
+
+static int
+ifflags_clear(int s, char * name, short flags)
+{
+    struct ifreq       ifr;
+    int                ret;
+
+    bzero(&ifr, sizeof(ifr));
+    strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+    ret = ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr);
+    if (ret < 0) {
+               return (ret);
+    }
+    ifr.ifr_flags &= ~flags;
+    return (ioctl(s, SIOCSIFFLAGS, &ifr));
+}
+
+static void
+mark_if_up(char * name)
+{
+       int s = dgram_socket(AF_INET);
+       if (s < 0)
+               return;
+       ifflags_set(s, name, IFF_UP);
+       close(s);
+}
+
+static void
+mark_if_down(char * name)
+{
+       int s = dgram_socket(AF_INET);
+       if (s < 0)
+               return;
+       ifflags_clear(s, name, IFF_UP);
+       close(s);
+}
+
+static void
+logEvent(CFStringRef evStr, struct kern_event_msg *ev_msg)
+{
+       int     i;
+       int     j;
+
+       SCLog(_verbose, LOG_DEBUG, CFSTR("%@ event:"), evStr);
+       SCLog(_verbose, LOG_DEBUG,
+             CFSTR("  Event size=%d, id=%d, vendor=%d, class=%d, subclass=%d, code=%d"),
+             ev_msg->total_size,
+             ev_msg->id,
+             ev_msg->vendor_code,
+             ev_msg->kev_class,
+             ev_msg->kev_subclass,
+             ev_msg->event_code);
+       for (i = 0, j = KEV_MSG_HEADER_SIZE; j < ev_msg->total_size; i++, j+=4) {
+               SCLog(_verbose, LOG_DEBUG, CFSTR("  Event data[%2d] = %08lx"), i, ev_msg->event_data[i]);
+       }
+}
+
+static const char *
+inetEventNameString(u_long event_code)
+{
+       if (event_code <= KEV_INET_ARPCOLLISION) {
+               return (inetEventName[event_code]);
+       }
+       return ("New Apple network INET subcode");
+}
+
+static const char *
+inet6EventNameString(u_long event_code)
+{
+       if (event_code <= KEV_INET6_DEFROUTER) {
+               return (inet6EventName[event_code]);
+       }
+       return ("New Apple network INET6 subcode");
+}
+
+static const char *
+dlEventNameString(u_long event_code)
+{
+       if (event_code <= KEV_DL_PROTO_DETACHED) {
+               return (dlEventName[event_code]);
+       }
+       return ("New Apple network DL subcode");
+}
+
+static const char *
+atalkEventNameString(u_long event_code)
+{
+       if (event_code <= KEV_ATALK_ZONELISTCHANGED) {
+               return (atalkEventName[event_code]);
+       }
+       return ("New Apple network AppleTalk subcode");
+}
+
+
+static void
+copy_if_name(struct net_event_data * ev, char * ifr_name, int ifr_len)
+{
+       snprintf(ifr_name, ifr_len, "%s%ld", ev->if_name, ev->if_unit);
+       return;
+}
+
+static void
+processEvent_Apple_Network(struct kern_event_msg *ev_msg)
+{
+       const char *                    eventName = NULL;
+       int                             dataLen = (ev_msg->total_size - KEV_MSG_HEADER_SIZE);
+       void *                          event_data = &ev_msg->event_data[0];
+       Boolean                         handled = TRUE;
+       char                            ifr_name[IFNAMSIZ+1];
+
+       switch (ev_msg->kev_subclass) {
+               case KEV_INET_SUBCLASS : {
+                       eventName = inetEventNameString(ev_msg->event_code);
+                       switch (ev_msg->event_code) {
+                               case KEV_INET_NEW_ADDR :
+                               case KEV_INET_CHANGED_ADDR :
+                               case KEV_INET_ADDR_DELETED :
+                               case KEV_INET_SIFDSTADDR :
+                               case KEV_INET_SIFBRDADDR :
+                               case KEV_INET_SIFNETMASK : {
+                                       struct kev_in_data * ev;
+
+                                       ev = (struct kev_in_data *)event_data;
+                                       if (dataLen < sizeof(*ev)) {
+                                               handled = FALSE;
+                                               break;
+                                       }
+                                       copy_if_name(&ev->link_data, ifr_name, sizeof(ifr_name));
+                                       interface_update_ipv4(NULL, ifr_name);
+                                       break;
+                               }
+                               case KEV_INET_ARPCOLLISION : {
+                                       struct kev_in_collision * ev;
+
+                                       ev = (struct kev_in_collision *)event_data;
+                                       if ((dataLen < sizeof(*ev))
+                                           || (dataLen < (sizeof(*ev) + ev->hw_len))) {
+                                               handled = FALSE;
+                                               break;
+                                       }
+                                       copy_if_name(&ev->link_data, ifr_name, sizeof(ifr_name));
+                                       interface_collision_ipv4(ifr_name,
+                                                                ev->ia_ipaddr,
+                                                                ev->hw_len,
+                                                                ev->hw_addr);
+                                       break;
+                               }
+                               default :
+                                       handled = FALSE;
+                                       break;
+                       }
+                       break;
+               }
+               case KEV_INET6_SUBCLASS : {
+                       struct kev_in6_data * ev;
+
+                       eventName = inet6EventNameString(ev_msg->event_code);
+                       ev = (struct kev_in6_data *)event_data;
+                       switch (ev_msg->event_code) {
+                               case KEV_INET6_NEW_USER_ADDR :
+                               case KEV_INET6_CHANGED_ADDR :
+                               case KEV_INET6_ADDR_DELETED :
+                               case KEV_INET6_NEW_LL_ADDR :
+                               case KEV_INET6_NEW_RTADV_ADDR :
+                               case KEV_INET6_DEFROUTER :
+                                       if (dataLen < sizeof(*ev)) {
+                                               handled = FALSE;
+                                               break;
+                                       }
+                                       copy_if_name(&ev->link_data, ifr_name, sizeof(ifr_name));
+                                       interface_update_ipv6(NULL, ifr_name);
+                                       break;
+
+                               default :
+                                       handled = FALSE;
+                                       break;
+                       }
+                       break;
+               }
+               case KEV_DL_SUBCLASS : {
+                       struct net_event_data * ev;
+
+                       eventName = dlEventNameString(ev_msg->event_code);
+                       ev = (struct net_event_data *)event_data;
+                       switch (ev_msg->event_code) {
+                               case KEV_DL_IF_ATTACHED :
+                                       /*
+                                        * new interface added
+                                        */
+                                       if (dataLen < sizeof(*ev)) {
+                                               handled = FALSE;
+                                               break;
+                                       }
+                                       copy_if_name(ev, ifr_name, sizeof(ifr_name));
+                                       link_add(ifr_name);
+                                       break;
+
+                               case KEV_DL_IF_DETACHED :
+                                       /*
+                                        * interface removed
+                                        */
+                                       if (dataLen < sizeof(*ev)) {
+                                               handled = FALSE;
+                                               break;
+                                       }
+                                       copy_if_name(ev, ifr_name, sizeof(ifr_name));
+                                       link_remove(ifr_name);
+                                       break;
+
+                               case KEV_DL_IF_DETACHING :
+                                       /*
+                                        * interface detaching
+                                        */
+                                       if (dataLen < sizeof(*ev)) {
+                                               handled = FALSE;
+                                               break;
+                                       }
+                                       copy_if_name(ev, ifr_name, sizeof(ifr_name));
+                                       interface_detaching(ifr_name);
+                                       break;
+
+                               case KEV_DL_SIFFLAGS :
+                               case KEV_DL_SIFMETRICS :
+                               case KEV_DL_SIFMTU :
+                               case KEV_DL_SIFPHYS :
+                               case KEV_DL_SIFMEDIA :
+                               case KEV_DL_SIFGENERIC :
+                               case KEV_DL_ADDMULTI :
+                               case KEV_DL_DELMULTI :
+                                       handled = FALSE;
+                                       break;
+
+                               case KEV_DL_PROTO_ATTACHED :
+                               case KEV_DL_PROTO_DETACHED : {
+                                       struct kev_dl_proto_data * protoEvent;
+
+                                       protoEvent = (struct kev_dl_proto_data *)event_data;
+                                       if (dataLen < sizeof(*protoEvent)) {
+                                               handled = FALSE;
+                                               break;
+                                       }
+                                       copy_if_name(&protoEvent->link_data,
+                                                    ifr_name, sizeof(ifr_name));
+                                       if (protoEvent->proto_remaining_count == 0) {
+                                               mark_if_down(ifr_name);
+                                       } else {
+                                               mark_if_up(ifr_name);
+                                       }
+                                       break;
+                               }
+
+                               case KEV_DL_LINK_OFF :
+                               case KEV_DL_LINK_ON :
+                                       /*
+                                        * update the link status in the store
+                                        */
+                                       if (dataLen < sizeof(*ev)) {
+                                               handled = FALSE;
+                                               break;
+                                       }
+                                       copy_if_name(ev, ifr_name, sizeof(ifr_name));
+                                       link_update_status(ifr_name, FALSE);
+                                       break;
+
+                               default :
+                                       handled = FALSE;
+                                       break;
+                       }
+                       break;
+               }
+               case KEV_ATALK_SUBCLASS: {
+                       struct kev_atalk_data * ev;
+
+                       eventName = atalkEventNameString(ev_msg->event_code);
+                       ev = (struct kev_atalk_data *)event_data;
+                       if (dataLen < sizeof(*ev)) {
+                               handled = FALSE;
+                               break;
+                       }
+                       copy_if_name(&ev->link_data, ifr_name, sizeof(ifr_name));
+                       switch (ev_msg->event_code) {
+                               case KEV_ATALK_ENABLED:
+                                       interface_update_atalk_address(ev, ifr_name);
+                                       break;
+
+                               case KEV_ATALK_DISABLED:
+                                       interface_update_shutdown_atalk();
+                                       break;
+
+                               case KEV_ATALK_ZONEUPDATED:
+                                       interface_update_atalk_zone(ev, ifr_name);
+                                       break;
+
+                               case KEV_ATALK_ROUTERUP:
+                               case KEV_ATALK_ROUTERUP_INVALID:
+                               case KEV_ATALK_ROUTERDOWN:
+                                       interface_update_appletalk(NULL, ifr_name);
+                                       break;
+
+                               case KEV_ATALK_ZONELISTCHANGED:
+                                       break;
+
+                               default :
+                                       handled = FALSE;
+                                       break;
+                       }
+                       break;
+               }
+               default :
+                       handled = FALSE;
+                       break;
+       }
+
+       if (handled == FALSE) {
+               CFStringRef     evStr;
+
+               evStr = CFStringCreateWithCString(NULL,
+                                                 (eventName != NULL) ? eventName : "New Apple network subclass",
+                                                 kCFStringEncodingASCII);
+               logEvent(evStr, ev_msg);
+               CFRelease(evStr);
+       }
+       return;
+}
+
+
+static void
+processEvent_Apple_IOKit(struct kern_event_msg *ev_msg)
+{
+       switch (ev_msg->kev_subclass) {
+               default :
+                       logEvent(CFSTR("New Apple IOKit subclass"), ev_msg);
+                       break;
+       }
+
+       return;
+}
+
+
+static void
+eventCallback(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info)
+{
+       int                     so              = CFSocketGetNative(s);
+       int                     status;
+       char                    buf[1024];
+       struct kern_event_msg   *ev_msg         = (struct kern_event_msg *)&buf[0];
+       int                     offset          = 0;
+
+       status = recv(so, &buf, sizeof(buf), 0);
+       if (status == -1) {
+               SCLog(TRUE, LOG_ERR, CFSTR("recv() failed: %s"), strerror(errno));
+               goto error;
+       }
+
+       cache_open();
+
+       while (offset < status) {
+               if ((offset + ev_msg->total_size) > status) {
+                       SCLog(TRUE, LOG_NOTICE, CFSTR("missed SYSPROTO_EVENT event, buffer not big enough"));
+                       break;
+               }
+
+               switch (ev_msg->vendor_code) {
+                       case KEV_VENDOR_APPLE :
+                               switch (ev_msg->kev_class) {
+                                       case KEV_NETWORK_CLASS :
+                                               processEvent_Apple_Network(ev_msg);
+                                               break;
+                                       case KEV_IOKIT_CLASS :
+                                               processEvent_Apple_IOKit(ev_msg);
+                                               break;
+                                       default :
+                                               /* unrecognized (Apple) event class */
+                                               logEvent(CFSTR("New (Apple) class"), ev_msg);
+                                               break;
+                               }
+                               break;
+                       default :
+                               /* unrecognized vendor code */
+                               logEvent(CFSTR("New vendor"), ev_msg);
+                               break;
+               }
+               offset += ev_msg->total_size;
+               ev_msg = (struct kern_event_msg *)&buf[offset];
+       }
+
+       cache_write(store);
+       cache_close();
+
+       return;
+
+    error :
+
+       SCLog(TRUE, LOG_ERR, CFSTR("kernel event monitor disabled."));
+       CFSocketInvalidate(s);
+       return;
+
+}
+
+
+__private_extern__
+void
+prime_KernelEventMonitor()
+{
+       struct ifaddrs  *ifap   = NULL;
+       struct ifaddrs  *scan;
+       int             sock    = -1;
+
+       SCLog(_verbose, LOG_DEBUG, CFSTR("prime() called"));
+
+       cache_open();
+
+       sock = dgram_socket(AF_INET);
+       if (sock == -1) {
+               SCLog(TRUE, LOG_ERR, CFSTR("could not get interface list, socket() failed: %s"), strerror(errno));
+               goto done;
+       }
+
+       if (getifaddrs(&ifap) < 0) {
+               SCLog(TRUE,
+                     LOG_ERR,
+                     CFSTR("could not get interface info, getifaddrs() failed: %s"),
+                     strerror(errno));
+               goto done;
+       }
+
+       /* update list of interfaces & link status */
+       for (scan = ifap; scan != NULL; scan = scan->ifa_next) {
+               if (scan->ifa_addr == NULL
+                   || scan->ifa_addr->sa_family != AF_LINK) {
+                       continue;
+               }
+               /* get the per-interface link/media information */
+               link_add(scan->ifa_name);
+       }
+
+       /*
+        * update IPv4 network addresses already assigned to
+        * the interfaces.
+        */
+       interface_update_ipv4(ifap, NULL);
+
+       /*
+        * update IPv6 network addresses already assigned to
+        * the interfaces.
+        */
+       interface_update_ipv6(ifap, NULL);
+
+       /*
+        * update AppleTalk network addresses already assigned
+        * to the interfaces.
+        */
+       interface_update_appletalk(ifap, NULL);
+
+       freeifaddrs(ifap);
+
+ done:
+       if (sock >= 0)
+               close(sock);
+
+       cache_write(store);
+       cache_close();
+
+       return;
+}
+
+
+__private_extern__
+void
+load_KernelEventMonitor(CFBundleRef bundle, Boolean bundleVerbose)
+{
+       int                     so;
+       int                     status;
+       struct kev_request      kev_req;
+       CFSocketRef             es;
+       CFSocketContext         context = { 0, NULL, NULL, NULL, NULL };
+       CFRunLoopSourceRef      rls;
+
+       if (bundleVerbose) {
+               _verbose = TRUE;
+       }
+
+       SCLog(_verbose, LOG_DEBUG, CFSTR("load() called"));
+       SCLog(_verbose, LOG_DEBUG, CFSTR("  bundle ID = %@"), CFBundleGetIdentifier(bundle));
+
+       /* open a "configd" session to allow cache updates */
+       store = SCDynamicStoreCreate(NULL,
+                                    CFSTR("Kernel Event Monitor plug-in"),
+                                    NULL,
+                                    NULL);
+       if (!store) {
+               SCLog(TRUE, LOG_ERR, CFSTR("SCDnamicStoreCreate() failed: %s"), SCErrorString(SCError()));
+               SCLog(TRUE, LOG_ERR, CFSTR("kernel event monitor disabled."));
+               return;
+       }
+
+       /* Open an event socket */
+       so = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT);
+       if (so != -1) {
+               /* establish filter to return all events */
+               kev_req.vendor_code  = 0;
+               kev_req.kev_class    = 0;       /* Not used if vendor_code is 0 */
+               kev_req.kev_subclass = 0;       /* Not used if either kev_class OR vendor_code are 0 */
+               status = ioctl(so, SIOCSKEVFILT, &kev_req);
+               if (status) {
+                       SCLog(TRUE, LOG_ERR, CFSTR("could not establish event filter, ioctl() failed: %s"), strerror(errno));
+                       (void) close(so);
+                       so = -1;
+               }
+       } else {
+               SCLog(TRUE, LOG_ERR, CFSTR("could not open event socket, socket() failed: %s"), strerror(errno));
+       }
+
+       if (so != -1) {
+               int     yes = 1;
+
+               status = ioctl(so, FIONBIO, &yes);
+               if (status) {
+                       SCLog(TRUE, LOG_ERR, CFSTR("could not set non-blocking io, ioctl() failed: %s"), strerror(errno));
+                       (void) close(so);
+                       so = -1;
+               }
+       }
+
+       if (so == -1) {
+               SCLog(TRUE, LOG_ERR, CFSTR("kernel event monitor disabled."));
+               CFRelease(store);
+               return;
+       }
+
+       /* Create a CFSocketRef for the PF_SYSTEM kernel event socket */
+       es  = CFSocketCreateWithNative(NULL,
+                                      so,
+                                      kCFSocketReadCallBack,
+                                      eventCallback,
+                                      &context);
+
+       /* Create and add a run loop source for the event socket */
+       rls = CFSocketCreateRunLoopSource(NULL, es, 0);
+       CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
+       CFRelease(rls);
+       CFRelease(es);
+
+       return;
+}
+
+#ifdef MAIN
+
+#include "ev_dlil.c"
+
+#define appendAddress  appendAddress_v4
+#define getIF          getIF_v4
+#define updateStore    updateStore_v4
+#include "ev_ipv4.c"
+#undef appendAddress
+#undef getIF
+#undef updateStore
+
+#define appendAddress  appendAddress_v6
+#define getIF          getIF_v6
+#define updateStore    updateStore_v6
+#include "ev_ipv6.c"
+#undef appendAddress
+#undef getIF
+#undef updateStore
+
+#define getIF          getIF_at
+#define updateStore    updateStore_at
+#include "ev_appletalk.c"
+#undef getIF
+#undef updateStore
+
+int
+main(int argc, char **argv)
+{
+       _sc_log     = FALSE;
+       _sc_verbose = (argc > 1) ? TRUE : FALSE;
+
+       load_KernelEventMonitor(CFBundleGetMainBundle(), (argc > 1) ? TRUE : FALSE);
+       prime_KernelEventMonitor();
+       CFRunLoopRun();
+       /* not reached */
+       exit(0);
+       return 0;
+}
+#endif