2 * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
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
33 * August 8, 2002 Allan Nathanson <ajn@apple.com>
34 * - added support for KEV_INET6_xxx events
36 * January 6, 2002 Jessica Vazquez <vazquez@apple.com>
37 * - added handling for KEV_ATALK_xxx events
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
45 * June 23, 2001 Allan Nathanson <ajn@apple.com>
46 * - update to public SystemConfiguration.framework APIs
48 * May 17, 2001 Allan Nathanson <ajn@apple.com>
49 * - add/maintain per-interface address/netmask/destaddr information
50 * in the dynamic store.
52 * June 30, 2000 Allan Nathanson <ajn@apple.com>
61 #include <sys/sysctl.h>
62 #include <sys/kern_event.h>
63 #include <nw/private.h>
64 #include <netinet6/nd6.h>
66 static dispatch_queue_t S_kev_queue
;
67 static dispatch_source_t S_kev_source
;
68 __private_extern__ Boolean network_changed
= FALSE
;
69 __private_extern__ SCDynamicStoreRef store
= NULL
;
70 __private_extern__ Boolean _verbose
= FALSE
;
73 __private_extern__ os_log_t
74 __log_KernelEventMonitor(void)
76 static os_log_t log
= NULL
;
79 log
= os_log_create("com.apple.SystemConfiguration", "KernelEventMonitor");
86 #define MESSAGES_MAX 100
87 static CFMutableArrayRef S_messages
;
88 static Boolean S_messages_modified
;
93 S_messages
= CFArrayCreateMutable(NULL
,
95 &kCFTypeArrayCallBacks
);
102 if (S_messages
!= NULL
) {
103 CFRelease(S_messages
);
110 messages_should_add_message(void)
112 if (S_messages
== NULL
113 || CFArrayGetCount(S_messages
) >= MESSAGES_MAX
) {
120 messages_add_message(CFStringRef message
)
122 if (messages_should_add_message()) {
123 CFArrayAppendValue(S_messages
, message
);
124 S_messages_modified
= TRUE
;
129 __private_extern__
void
130 messages_add_msg_with_arg(const char * msg
, const char * arg
)
132 if (messages_should_add_message()) {
135 str
= CFStringCreateWithFormat(NULL
, NULL
,
136 CFSTR("%12.8f: %s %s"),
137 CFAbsoluteTimeGetCurrent(),
139 messages_add_message(str
);
148 if (S_messages
!= NULL
&& S_messages_modified
) {
149 SCDynamicStoreSetValue(NULL
,
150 CFSTR("Plugin:KernelEventMonitor"),
152 S_messages_modified
= FALSE
;
158 check_interface_link_status(const char * if_name
)
160 if (S_messages
== NULL
) {
161 return; /* we're not in early boot of system */
163 link_update_status_if_missing(if_name
);
169 dgram_socket(int domain
)
173 s
= socket(domain
, SOCK_DGRAM
, 0);
175 SC_log(LOG_ERR
, "socket() failed: %s", strerror(errno
));
182 post_network_changed(void)
184 if (network_changed
) {
187 status
= notify_post(_SC_NOTIFY_NETWORK_CHANGE
);
188 if (status
!= NOTIFY_STATUS_OK
) {
189 SC_log(LOG_NOTICE
, "notify_post() failed: error=%u", status
);
192 network_changed
= FALSE
;
199 logEvent(CFStringRef evStr
, struct kern_event_msg
*ev_msg
)
208 SC_log(LOG_DEBUG
, "%@ event:", evStr
);
209 SC_log(LOG_DEBUG
, " Event size=%d, id=%d, vendor=%d, class=%d, subclass=%d, code=%d",
214 ev_msg
->kev_subclass
,
216 for (i
= 0, j
= KEV_MSG_HEADER_SIZE
; j
< ev_msg
->total_size
; i
++, j
+=4) {
217 SC_log(LOG_DEBUG
, " Event data[%2d] = %08x", i
, ev_msg
->event_data
[i
]);
222 copy_if_name(const struct net_event_data
* ev
, char * ifr_name
, int ifr_len
)
224 snprintf(ifr_name
, ifr_len
, "%s%d", ev
->if_name
, ev
->if_unit
);
228 static uint8_t info_zero
[DLIL_MODARGLEN
];
231 processEvent_Apple_Network(struct kern_event_msg
*ev_msg
)
233 size_t dataLen
= (ev_msg
->total_size
- KEV_MSG_HEADER_SIZE
);
234 void * event_data
= &ev_msg
->event_data
[0];
235 char ifr_name
[IFNAMSIZ
];
236 Boolean handled
= TRUE
;
238 switch (ev_msg
->kev_subclass
) {
239 case KEV_INET_SUBCLASS
: {
240 switch (ev_msg
->event_code
) {
241 case KEV_INET_NEW_ADDR
:
242 case KEV_INET_CHANGED_ADDR
:
243 case KEV_INET_ADDR_DELETED
:
244 case KEV_INET_SIFDSTADDR
:
245 case KEV_INET_SIFBRDADDR
:
246 case KEV_INET_SIFNETMASK
: {
247 struct kev_in_data
* ev
;
249 ev
= (struct kev_in_data
*)event_data
;
250 if (dataLen
< sizeof(*ev
)) {
254 copy_if_name(&ev
->link_data
, ifr_name
, sizeof(ifr_name
));
255 SC_log(LOG_INFO
, "Process IPv4 address change: %s: %d", (char *)ifr_name
, ev_msg
->event_code
);
256 ipv4_interface_update(NULL
, ifr_name
);
257 if (ev_msg
->event_code
258 != KEV_INET_ADDR_DELETED
) {
259 check_interface_link_status(ifr_name
);
263 case KEV_INET_ARPCOLLISION
: {
264 struct kev_in_collision
* ev
;
266 ev
= (struct kev_in_collision
*)event_data
;
267 if ((dataLen
< sizeof(*ev
))
268 || (dataLen
< (sizeof(*ev
) + ev
->hw_len
))) {
272 copy_if_name(&ev
->link_data
, ifr_name
, sizeof(ifr_name
));
273 SC_log(LOG_INFO
, "Process ARP collision: %s", (char *)ifr_name
);
274 ipv4_arp_collision(ifr_name
,
280 #if !TARGET_OS_IPHONE
281 case KEV_INET_PORTINUSE
: {
282 struct kev_in_portinuse
* ev
;
283 ev
= (struct kev_in_portinuse
*)event_data
;
284 if (dataLen
< sizeof(*ev
)) {
288 SC_log(LOG_INFO
, "Process port-in-use: %hu, %u", ev
->port
, ev
->req_pid
);
289 ipv4_port_in_use(ev
->port
, ev
->req_pid
);
292 #endif /* !TARGET_OS_IPHONE */
293 case KEV_INET_ARPRTRFAILURE
: {
294 const struct kev_in_arpfailure
* ev
;
296 ev
= (const struct kev_in_arpfailure
*)event_data
;
297 if (dataLen
< sizeof(*ev
)) {
301 copy_if_name(&ev
->link_data
, ifr_name
, sizeof(ifr_name
));
302 SC_log(LOG_INFO
, "Process router ARP failure: %s", (char *)ifr_name
);
303 ipv4_router_arp_failure(ifr_name
);
306 case KEV_INET_ARPRTRALIVE
: {
307 const struct kev_in_arpalive
* ev
;
309 ev
= (const struct kev_in_arpalive
*)event_data
;
310 if (dataLen
< sizeof(*ev
)) {
314 copy_if_name(&ev
->link_data
, ifr_name
, sizeof(ifr_name
));
315 SC_log(LOG_INFO
, "Process router ARP alive: %s", (char *)ifr_name
);
316 ipv4_router_arp_alive(ifr_name
);
325 case KEV_INET6_SUBCLASS
: {
326 struct kev_in6_data
* ev
;
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 if (dataLen
< sizeof(*ev
)) {
339 copy_if_name(&ev
->link_data
, ifr_name
, sizeof(ifr_name
));
340 SC_log(LOG_INFO
, "Process IPv6 address change: %s: %d", (char *)ifr_name
, ev_msg
->event_code
);
341 interface_update_ipv6(NULL
, ifr_name
);
342 if (ev_msg
->event_code
== KEV_INET6_NEW_USER_ADDR
343 && (ev
->ia6_flags
& IN6_IFF_DUPLICATED
) != 0) {
344 ipv6_duplicated_address(ifr_name
,
345 &ev
->ia_addr
.sin6_addr
,
349 if (ev_msg
->event_code
350 != KEV_INET6_ADDR_DELETED
) {
351 check_interface_link_status(ifr_name
);
355 case KEV_INET6_REQUEST_NAT64_PREFIX
:
356 if (dataLen
< sizeof(*ev
)) {
360 copy_if_name(&ev
->link_data
, ifr_name
, sizeof(ifr_name
));
361 SC_log(LOG_INFO
, "Process NAT64 prefix request: %s", (char *)ifr_name
);
362 nat64_prefix_request(ifr_name
);
371 case KEV_DL_SUBCLASS
: {
372 struct net_event_data
* ev
;
374 ev
= (struct net_event_data
*)event_data
;
375 switch (ev_msg
->event_code
) {
376 case KEV_DL_IF_ATTACHED
:
378 * new interface added
380 if (dataLen
< sizeof(*ev
)) {
384 copy_if_name(ev
, ifr_name
, sizeof(ifr_name
));
385 SC_log(LOG_INFO
, "Process interface attach: %s", (char *)ifr_name
);
389 case KEV_DL_IF_DETACHED
:
393 if (dataLen
< sizeof(*ev
)) {
397 copy_if_name(ev
, ifr_name
, sizeof(ifr_name
));
398 SC_log(LOG_INFO
, "Process interface detach: %s", (char *)ifr_name
);
399 link_remove(ifr_name
);
402 case KEV_DL_IF_DETACHING
:
404 * interface detaching
406 if (dataLen
< sizeof(*ev
)) {
410 copy_if_name(ev
, ifr_name
, sizeof(ifr_name
));
411 SC_log(LOG_INFO
, "Process interface detaching: %s", (char *)ifr_name
);
412 interface_detaching(ifr_name
);
415 case KEV_DL_PROTO_ATTACHED
:
416 case KEV_DL_PROTO_DETACHED
: {
417 struct kev_dl_proto_data
* protoEvent
;
419 protoEvent
= (struct kev_dl_proto_data
*)event_data
;
420 if (dataLen
< sizeof(*protoEvent
)) {
424 copy_if_name(&protoEvent
->link_data
,
425 ifr_name
, sizeof(ifr_name
));
426 SC_log(LOG_INFO
, "Process protocol %s: %s (pf=%d, n=%d)",
427 (ev_msg
->event_code
== KEV_DL_PROTO_ATTACHED
) ? "attach" : "detach",
429 protoEvent
->proto_family
,
430 protoEvent
->proto_remaining_count
);
434 #ifdef KEV_DL_IF_IDLE_ROUTE_REFCNT
435 case KEV_DL_IF_IDLE_ROUTE_REFCNT
: {
437 * interface route refcnt idle
439 if (dataLen
< sizeof(*ev
)) {
443 copy_if_name(ev
, ifr_name
, sizeof(ifr_name
));
444 SC_log(LOG_INFO
, "Process interface idle: %s", (char *)ifr_name
);
445 interface_update_idle_state(ifr_name
);
448 #endif // KEV_DL_IF_IDLE_ROUTE_REFCNT
450 case KEV_DL_IFDELEGATE_CHANGED
: {
452 * interface delegation changed
454 if (dataLen
< sizeof(*ev
)) {
458 copy_if_name(ev
, ifr_name
, sizeof(ifr_name
));
459 SC_log(LOG_INFO
, "Process interface delegation change: %s", (char *)ifr_name
);
460 interface_update_delegation(ifr_name
);
464 case KEV_DL_LINK_OFF
:
465 case KEV_DL_LINK_ON
:
467 * update the link status in the store
469 if (dataLen
< sizeof(*ev
)) {
473 copy_if_name(ev
, ifr_name
, sizeof(ifr_name
));
474 SC_log(LOG_INFO
, "Process interface link %s: %s",
475 (ev_msg
->event_code
== KEV_DL_LINK_ON
) ? "up" : "down",
477 link_update_status(ifr_name
, FALSE
, FALSE
);
480 #ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED
481 case KEV_DL_LINK_QUALITY_METRIC_CHANGED
: {
482 struct kev_dl_link_quality_metric_data
* lqm_data
;
483 lqm_data
= (struct kev_dl_link_quality_metric_data
*) event_data
;
485 if (dataLen
< sizeof(*ev
)) {
489 copy_if_name(ev
, ifr_name
, sizeof(ifr_name
));
490 SC_log(LOG_INFO
, "Process interface quality: %s (q=%d)",
492 lqm_data
->link_quality_metric
);
493 interface_update_quality_metric(ifr_name
,
494 lqm_data
->link_quality_metric
);
497 #endif // KEV_DL_LINK_QUALITY_METRIC_CHANGED
500 case KEV_DL_ISSUES
: {
501 struct kev_dl_issues
*issues
;
503 issues
= (struct kev_dl_issues
*)event_data
;
504 if (dataLen
< sizeof(*ev
)) {
508 copy_if_name(ev
, ifr_name
, sizeof(ifr_name
));
509 SC_log(LOG_INFO
, "Process interface link issues: %s",
511 interface_update_link_issues(ifr_name
,
516 (bcmp(issues
->info
, info_zero
, DLIL_MODARGLEN
) != 0)
521 #endif // KEV_DL_ISSUES
529 #ifdef KEV_NETPOLICY_SUBCLASS
530 case KEV_NETPOLICY_SUBCLASS
: {
533 #endif // KEV_NETPOLICY_SUBCLASS
535 #ifdef KEV_SOCKET_SUBCLASS
536 case KEV_SOCKET_SUBCLASS
: {
539 #endif // KEV_SOCKET_SUBCLASS
541 #ifdef KEV_ND6_SUBCLASS
542 case KEV_ND6_SUBCLASS
: {
543 struct kev_nd6_event
* ev
;
545 ev
= (struct kev_nd6_event
*)event_data
;
546 switch (ev_msg
->event_code
) {
547 case KEV_ND6_ADDR_DETACHED
:
548 case KEV_ND6_ADDR_DEPRECATED
:
549 case KEV_ND6_ADDR_EXPIRED
:
550 if (dataLen
< sizeof(*ev
)) {
554 copy_if_name(&ev
->link_data
, ifr_name
, sizeof(ifr_name
));
555 SC_log(LOG_INFO
, "Process ND6 address change: %s: %d", (char *)ifr_name
, ev_msg
->event_code
);
556 interface_update_ipv6(NULL
, ifr_name
);
558 case KEV_ND6_RTR_EXPIRED
:
559 if (dataLen
< sizeof(*ev
)) {
563 copy_if_name(&ev
->link_data
, ifr_name
, sizeof(ifr_name
));
564 SC_log(LOG_INFO
, "Process IPv6 router expired: %s: %d", (char *)ifr_name
, ev_msg
->event_code
);
565 ipv6_router_expired(ifr_name
);
572 #endif // KEV_ND6_SUBCLASS
574 #ifdef KEV_NECP_SUBCLASS
575 case KEV_NECP_SUBCLASS
: {
578 #endif // KEV_NECP_SUBCLASS
580 #ifdef KEV_NETAGENT_SUBCLASS
581 case KEV_NETAGENT_SUBCLASS
: {
584 #endif // KEV_NETAGENT_SUBCLASS
586 #ifdef KEV_LOG_SUBCLASS
587 case KEV_LOG_SUBCLASS
: {
590 #endif // KEV_LOG_SUBCLASS
592 #ifdef KEV_NETEVENT_SUBCLASS
593 case KEV_NETEVENT_SUBCLASS
: {
596 #endif // KEV_NETEVENT_SUBCLASS
603 logEvent(CFSTR("Error processing (Apple network subclass)"), ev_msg
);
609 eventCallback(int so
)
613 struct kern_event_msg ev_msg1
; // first kernel event
615 struct kern_event_msg
*ev_msg
= &buf
.ev_msg1
;
619 status
= recv(so
, &buf
, sizeof(buf
), 0);
621 SC_log(LOG_NOTICE
, "recv() failed: %s", strerror(errno
));
625 _SCDynamicStoreCacheOpen(store
);
627 while (offset
< status
) {
628 if ((offset
+ (ssize_t
)ev_msg
->total_size
) > status
) {
629 SC_log(LOG_NOTICE
, "missed SYSPROTO_EVENT event, buffer not big enough");
633 switch (ev_msg
->vendor_code
) {
634 case KEV_VENDOR_APPLE
:
635 switch (ev_msg
->kev_class
) {
636 case KEV_NETWORK_CLASS
:
637 processEvent_Apple_Network(ev_msg
);
647 offset
+= ev_msg
->total_size
;
648 ev_msg
= (struct kern_event_msg
*)(void *)&buf
.bytes
[offset
];
651 _SCDynamicStoreCacheCommitChanges(store
);
652 _SCDynamicStoreCacheClose(store
);
653 post_network_changed();
660 __private_extern__
void
661 config_new_interface(const char * ifname
)
663 xpc_object_t if_list
;
665 if (ifname
== NULL
) {
666 network_config_check_interface_settings(NULL
);
669 if_list
= xpc_array_create(NULL
, 0);
670 xpc_array_set_string(if_list
, XPC_ARRAY_APPEND
, ifname
);
671 network_config_check_interface_settings(if_list
);
672 xpc_release(if_list
);
677 update_interfaces(const char * msg
, Boolean first_time
)
679 Boolean added
= FALSE
;
680 struct ifaddrs
* ifap
= NULL
;
681 CFMutableArrayRef ifList
= NULL
;
682 struct ifaddrs
* scan
;
684 if (getifaddrs(&ifap
) == -1) {
685 messages_add_msg_with_arg("getifaddrs", strerror(errno
));
686 SC_log(LOG_NOTICE
, "getifaddrs() failed: %s", strerror(errno
));
690 /* update list of interfaces & link status */
691 ifList
= interfaceListCopy();
692 for (scan
= ifap
; scan
!= NULL
; scan
= scan
->ifa_next
) {
693 if (scan
->ifa_addr
== NULL
694 || scan
->ifa_addr
->sa_family
!= AF_LINK
) {
697 /* get the per-interface link/media information */
698 if (interfaceListAddInterface(ifList
, scan
->ifa_name
)) {
699 messages_add_msg_with_arg(msg
, scan
->ifa_name
);
702 config_new_interface(scan
->ifa_name
);
707 /* update the global list if an interface was added */
709 interfaceListUpdate(ifList
);
713 /* update IPv4/IPv6 addresses that are already assigned */
715 ipv4_interface_update(ifap
, NULL
);
716 interface_update_ipv6(ifap
, NULL
);
723 /* tell networkd to get the interface list itself */
724 config_new_interface(NULL
);
729 #define TIMER_INTERVAL (6LL * NSEC_PER_SEC)
730 #define MAX_TIMER_COUNT 20
733 check_for_new_interfaces(void * context
);
738 dispatch_after_f(dispatch_time(DISPATCH_TIME_NOW
, TIMER_INTERVAL
),
741 check_for_new_interfaces
);
746 check_for_new_interfaces(void * context
)
748 #pragma unused(context)
754 /* update KEV driven content in case a message got dropped */
755 snprintf(msg
, sizeof(msg
), "update %d (of %d)", count
, MAX_TIMER_COUNT
);
756 _SCDynamicStoreCacheOpen(store
);
757 update_interfaces(msg
, FALSE
);
758 _SCDynamicStoreCacheCommitChanges(store
);
759 _SCDynamicStoreCacheClose(store
);
762 /* schedule the next timer, if needed */
763 if (count
< MAX_TIMER_COUNT
) {
776 SC_log(LOG_DEBUG
, "prime() called");
778 _SCDynamicStoreCacheOpen(store
);
780 update_interfaces("prime", TRUE
);
781 _SCDynamicStoreCacheCommitChanges(store
);
782 _SCDynamicStoreCacheClose(store
);
784 network_changed
= TRUE
;
785 post_network_changed();
788 /* start handling kernel events */
789 dispatch_resume(S_kev_source
);
791 /* schedule polling timer */
800 prime_KernelEventMonitor()
802 dispatch_async(S_kev_queue
, ^{ prime(); });
807 initialize_store(void)
809 store
= SCDynamicStoreCreate(NULL
,
810 CFSTR("Kernel Event Monitor plug-in"),
814 SC_log(LOG_ERR
, "SCDynamicStoreCreate() failed: %s", SCErrorString(SCError()));
823 load_KernelEventMonitor(CFBundleRef bundle
, Boolean bundleVerbose
)
825 struct kev_request kev_req
;
833 SC_log(LOG_DEBUG
, "load() called");
834 SC_log(LOG_DEBUG
, " bundle ID = %@", CFBundleGetIdentifier(bundle
));
836 if (!initialize_store()) {
837 SC_log(LOG_ERR
, "kernel event monitor disabled");
841 /* Open an event socket */
842 so
= socket(PF_SYSTEM
, SOCK_RAW
, SYSPROTO_EVENT
);
844 /* establish filter to return events of interest */
845 kev_req
.vendor_code
= KEV_VENDOR_APPLE
;
846 kev_req
.kev_class
= KEV_NETWORK_CLASS
;
847 kev_req
.kev_subclass
= KEV_ANY_SUBCLASS
;
848 status
= ioctl(so
, SIOCSKEVFILT
, &kev_req
);
850 SC_log(LOG_ERR
, "could not establish event filter, ioctl() failed: %s", strerror(errno
));
855 SC_log(LOG_ERR
, "could not open event socket, socket() failed: %s", strerror(errno
));
861 status
= ioctl(so
, FIONBIO
, &yes
);
863 SC_log(LOG_ERR
, "could not set non-blocking io, ioctl() failed: %s", strerror(errno
));
870 SC_log(LOG_ERR
, "kernel event monitor disabled");
875 S_kev_queue
= dispatch_queue_create("com.apple.SystemConfiguration.KernelEventMonitor", NULL
);
877 = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ
, so
, 0, S_kev_queue
);
878 dispatch_source_set_cancel_handler(S_kev_source
, ^{
881 dispatch_source_set_event_handler(S_kev_source
, ^{
884 ok
= eventCallback(so
);
886 SC_log(LOG_ERR
, "kernel event monitor disabled");
887 dispatch_source_cancel(S_kev_source
);
890 // NOTE: dispatch_resume() will be called in prime()
899 #define appendAddress appendAddress_v4
900 #define getIF getIF_v4
901 #define updateStore updateStore_v4
907 #define appendAddress appendAddress_v6
908 #define getIF getIF_v6
909 #define updateStore updateStore_v6
916 main(int argc
, char **argv
)
918 _sc_log
= kSCLogDestinationFile
;
919 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
921 load_KernelEventMonitor(CFBundleGetMainBundle(), (argc
> 1) ? TRUE
: FALSE
);
922 prime_KernelEventMonitor();