1/*
2 * Copyright (c) 2005-2014 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 * January 15, 2005		Allan Nathanson <ajn@apple.com>
28 * - initial revision
29 */
30
31#include <stdlib.h>
32#include <unistd.h>
33#include <sys/filio.h>
34#include <sys/ioctl.h>
35#include <sys/socket.h>
36#include <sys/time.h>
37#include <sys/types.h>
38#include <net/ethernet.h>
39#include <net/if.h>
40#include <net/if_dl.h>
41#include <net/if_media.h>
42#include <net/if_types.h>
43#include <net/if_var.h>
44#include <sys/kern_event.h>
45#include <netinet/in.h>
46#include <netinet/in_var.h>
47#include <netinet6/in6_var.h>
48#include <ifaddrs.h>
49#include <arpa/inet.h>
50
51#include <TargetConditionals.h>
52#include <CoreFoundation/CoreFoundation.h>
53#include <SystemConfiguration/SystemConfiguration.h>
54#include <SystemConfiguration/SCPrivate.h>
55#include <IOKit/IOKitLib.h>
56#include <IOKit/IOMessage.h>
57#include <IOKit/pwr_mgt/IOPM.h>
58#include <IOKit/pwr_mgt/IOPMLib.h>
59#include <IOKit/pwr_mgt/IOPMLibPrivate.h>
60
61#include <dnsinfo.h>
62#include <network_information.h>
63#include <notify.h>
64#ifndef	TARGET_OS_EMBEDDED
65#include <utmpx.h>
66#include <utmpx_thread.h>
67#endif	// !TARGET_OS_EMBEDDED
68
69
70/* generic MessageTracer keys */
71#define MSGTRACER_KEY_DOMAIN    "com.apple.message.domain"
72#define MSGTRACER_KEY_SIG       "com.apple.message.signature"
73#define MSGTRACER_KEY_UUID      "com.apple.message.uuid"
74#define MSGTRACER_KEY_VALUE1    "com.apple.message.value"
75
76
77#define MY_ASL_FACILITY		"com.apple.SystemConfiguration.Logger"
78#define MY_MSGTRACER_DOMAIN	"com.apple.network.log"
79
80
81static	asl_object_t	log_msg	= NULL;
82static	io_connect_t	power	= MACH_PORT_NULL;
83static	Boolean		verbose	= FALSE;
84
85
86static char *
87elapsed()
88{
89	static char		str[128];
90	struct tm		tm_diff;
91	struct tm		tm_now;
92	struct timeval		tv_diff;
93	struct timeval		tv_now;
94	static struct timeval	tv_then	= { 0, 0 };
95
96	(void)gettimeofday(&tv_now, NULL);
97
98	(void)localtime_r(&tv_now.tv_sec, &tm_now);
99
100	timersub(&tv_now, &tv_then, &tv_diff);
101	(void)localtime_r(&tv_diff.tv_sec, &tm_diff);
102#ifdef MAIN
103	sprintf(str, "%2d:%02d:%02d.%03d (+%ld.%03d)",
104		tm_now.tm_hour,
105		tm_now.tm_min,
106		tm_now.tm_sec,
107		tv_now.tv_usec / 1000,
108		tv_diff.tv_sec,
109		tv_diff.tv_usec / 1000);
110#else
111	sprintf(str, ".%03d (+%ld.%03d)",
112		tv_now.tv_usec / 1000,
113		tv_diff.tv_sec,
114		tv_diff.tv_usec / 1000);
115#endif
116
117	tv_then = tv_now;
118	return str;
119}
120
121
122#pragma mark -
123#pragma mark [Network] Kernel Events
124
125
126static CFStringRef
127copyInterfaceFlags(const char *if_name)
128{
129	const char *		iff_up		= "?  ";
130	struct ifreq		ifr;
131	const char		*ifm_active	= "?  ";
132	int			sock;
133	CFStringRef		str		= NULL;
134
135	sock = socket(AF_INET, SOCK_DGRAM, 0);
136	if (sock == -1) {
137		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("socket() failed"));
138		return NULL;
139	}
140
141	bzero((char *)&ifr, sizeof(ifr));
142	(void) strlcpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
143	if (ioctl(sock, SIOCGIFFLAGS, (caddr_t)&ifr) == 0) {
144		struct ifmediareq	ifm;
145
146		iff_up = (ifr.ifr_flags & IFF_UP) ? "yes" : "no ";
147
148		bzero((char *)&ifm, sizeof(ifm));
149		(void) strncpy(ifm.ifm_name, if_name, sizeof(ifm.ifm_name));
150		if ((ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifm) == 0) &&
151		    (ifm.ifm_count > 0) &&
152		    (ifm.ifm_status & IFM_AVALID)) {
153			ifm_active = (ifm.ifm_status & IFM_ACTIVE) ? "yes" : "no ";
154		}
155
156		str = CFStringCreateWithFormat(NULL,
157					       NULL,
158					       CFSTR("\n%-5s: IFF_UP = %s IFM_ACTIVE = %s"),
159					       if_name,
160					       iff_up,
161					       ifm_active);
162	}
163
164	(void)close(sock);
165
166	return str;
167}
168
169
170static int
171prefixLength(struct sockaddr_in6 *sin6)
172{
173	register u_int8_t	*name		= &sin6->sin6_addr.s6_addr[0];
174	register int		byte;
175	register int		bit;
176	int			plen		= 0;
177
178	for (byte = 0; byte < sizeof(struct in6_addr); byte++, plen += 8) {
179		if (name[byte] != 0xff) {
180			break;
181		}
182	}
183
184	if (byte == sizeof(struct in6_addr)) {
185		return plen;
186	}
187
188	for (bit = 7; bit != 0; bit--, plen++) {
189		if (!(name[byte] & (1 << bit))) {
190			break;
191		}
192	}
193
194	for (; bit != 0; bit--) {
195		if (name[byte] & (1 << bit)) {
196			return 0;
197		}
198	}
199
200	byte++;
201	for (; byte < sizeof(struct in6_addr); byte++) {
202		if (name[byte]) {
203			return 0;
204		}
205	}
206
207	return plen;
208}
209
210
211static void
212KernelEvent_notification(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info)
213{
214	int			so		= CFSocketGetNative(s);
215	size_t			status;
216	union {
217		char			bytes[1024];
218		struct kern_event_msg	ev_msg1;	// first kernel event
219	} buf;
220	struct kern_event_msg	*ev_msg		= &buf.ev_msg1;
221	size_t			offset		= 0;
222
223	status = recv(so, &buf, sizeof(buf), 0);
224	if (status == -1) {
225		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("recv() failed: %s"), strerror(errno));
226		CFSocketInvalidate(s);
227		return;
228	}
229
230	while (offset < status) {
231		if ((offset + ev_msg->total_size) > status) {
232			SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("missed SYSPROTO_EVENT event, buffer not big enough"));
233			break;
234		}
235
236		switch (ev_msg->vendor_code) {
237			case KEV_VENDOR_APPLE :
238				switch (ev_msg->kev_class) {
239					case KEV_NETWORK_CLASS : {
240						void	*event_data	= &ev_msg->event_data[0];
241
242						switch (ev_msg->kev_subclass) {
243							case KEV_DL_SUBCLASS : {
244								struct net_event_data	*ev;
245								char			if_name[IFNAMSIZ];
246
247								ev = (struct net_event_data *)event_data;
248
249								snprintf(if_name, IFNAMSIZ, "%s%d",
250									 ev->if_name,
251									 ev->if_unit);
252
253								switch (ev_msg->event_code) {
254									case KEV_DL_IF_ATTACHED : {
255										SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
256										      CFSTR("%s kernel event: %s: attached"),
257										      elapsed(),
258										      if_name);
259										break;
260									}
261									case KEV_DL_IF_DETACHING  : {
262										SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
263										      CFSTR("%s kernel event: %s: detaching"),
264										      elapsed(),
265										      if_name);
266										break;
267									}
268									case KEV_DL_IF_DETACHED  : {
269										SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
270										      CFSTR("%s kernel event: %s: detached"),
271										      elapsed(),
272										      if_name);
273										break;
274									}
275									case KEV_DL_LINK_OFF : {
276										CFStringRef	str;
277
278										str = verbose ? copyInterfaceFlags(if_name) : NULL;
279										SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
280										      CFSTR("%s kernel event: %s: link down%@"),
281										      elapsed(),
282										      if_name,
283										      str != NULL ? str : CFSTR(""));
284										if (str != NULL) CFRelease(str);
285										break;
286									}
287									case KEV_DL_LINK_ON  : {
288										CFStringRef	str;
289
290										str = verbose ? copyInterfaceFlags(if_name) : NULL;
291										SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
292										      CFSTR("%s kernel event: %s: link up%@"),
293										      elapsed(),
294										      if_name,
295										      str != NULL ? str : CFSTR(""));
296										if (str != NULL) CFRelease(str);
297										break;
298									}
299									default :
300										break;
301								}
302								break;
303							}
304							case KEV_INET_SUBCLASS : {
305								char			addr[128];
306								struct kev_in_data	*ev;
307								char			if_name[IFNAMSIZ];
308								char			mask[128];
309
310								ev = (struct kev_in_data *)event_data;
311
312								snprintf(if_name, IFNAMSIZ, "%s%d",
313									 ev->link_data.if_name,
314									 ev->link_data.if_unit);
315
316								switch (ev_msg->event_code) {
317									case KEV_INET_NEW_ADDR :
318									case KEV_INET_CHANGED_ADDR :
319									case KEV_INET_ADDR_DELETED : {
320										struct sockaddr_in	sin;
321
322										bzero(&sin, sizeof(sin));
323										sin.sin_len    = sizeof(sin);
324										sin.sin_family = AF_INET;
325										sin.sin_addr   = ev->ia_addr;
326										_SC_sockaddr_to_string((struct sockaddr *)&sin, addr, sizeof(addr));
327
328										bzero(&sin, sizeof(sin));
329										sin.sin_len         = sizeof(sin);
330										sin.sin_family      = AF_INET;
331										sin.sin_addr.s_addr = ntohl(ev->ia_subnetmask);
332										_SC_sockaddr_to_string((struct sockaddr *)&sin, mask, sizeof(mask));
333										break;
334									}
335									default :
336										break;
337								}
338
339								switch (ev_msg->event_code) {
340									case KEV_INET_NEW_ADDR : {
341										SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
342										      CFSTR("%s kernel event: %s: IPv4 address added (%s/%s)"),
343										      elapsed(),
344										      if_name,
345										      addr,
346										      mask);
347										break;
348									}
349									case KEV_INET_CHANGED_ADDR : {
350										SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
351										      CFSTR("%s kernel event: %s: IPv4 address changed (%s/%s)"),
352										      elapsed(),
353										      if_name,
354										      addr,
355										      mask);
356										break;
357									}
358									case KEV_INET_ADDR_DELETED : {
359										SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
360										      CFSTR("%s kernel event: %s: IPv4 address removed (%s/%s)"),
361										      elapsed(),
362										      if_name,
363										      addr,
364										      mask);
365										break;
366									}
367									default :
368										break;
369								}
370								break;
371							}
372							case KEV_INET6_SUBCLASS : {
373								char			addr[128];
374								struct kev_in6_data	*ev;
375								char			if_name[IFNAMSIZ];
376								int			plen	= 0;
377
378								ev = (struct kev_in6_data *)event_data;
379
380								snprintf(if_name, IFNAMSIZ, "%s%d",
381									 ev->link_data.if_name,
382									 ev->link_data.if_unit);
383
384								switch (ev_msg->event_code) {
385									case KEV_INET6_NEW_USER_ADDR :
386									case KEV_INET6_NEW_LL_ADDR :
387									case KEV_INET6_CHANGED_ADDR :
388									case KEV_INET6_ADDR_DELETED : {
389										_SC_sockaddr_to_string((struct sockaddr *)&ev->ia_addr, addr, sizeof(addr));
390										plen = prefixLength(&ev->ia_prefixmask);
391										break;
392									}
393									default :
394										break;
395								}
396
397								switch (ev_msg->event_code) {
398									case KEV_INET6_NEW_USER_ADDR :
399									case KEV_INET6_NEW_LL_ADDR   : {
400										SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
401										      CFSTR("%s kernel event: %s: IPv6 address added (%s/%d)"),
402										      elapsed(),
403										      if_name,
404										      addr,
405										      plen);
406										break;
407									}
408									case KEV_INET6_CHANGED_ADDR : {
409										SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
410										      CFSTR("%s kernel event: %s: IPv6 address changed (%s/%d)"),
411										      elapsed(),
412										      if_name,
413										      addr,
414										      plen);
415										break;
416									}
417									case KEV_INET6_ADDR_DELETED : {
418										SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
419										      CFSTR("%s kernel event: %s: IPv6 address removed"),
420										      elapsed(),
421										      if_name);
422										break;
423									}
424									default :
425										break;
426								}
427								break;
428							}
429							default :
430								break;
431						}
432						break;
433					}
434					default :
435						break;
436				}
437				break;
438			default :
439				/* unrecognized vendor code */
440				break;
441		}
442		offset += ev_msg->total_size;
443		ev_msg = (struct kern_event_msg *)(void *)&buf.bytes[offset];
444	}
445
446	return;
447}
448
449
450static void
451add_KernelEvent_notification()
452{
453	CFSocketRef		es;
454	CFSocketContext		es_context	= { 0, NULL, NULL, NULL, NULL };
455	struct kev_request	kev_req;
456	CFRunLoopSourceRef	rls;
457	int			so;
458	int			yes = 1;
459
460	/* Open an event socket */
461	so = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT);
462	if (so == -1) {
463		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("socket() failed"));
464		return;
465	}
466
467	/* establish filter to return all events */
468	kev_req.vendor_code  = KEV_VENDOR_APPLE;
469	kev_req.kev_class    = KEV_NETWORK_CLASS;
470	kev_req.kev_subclass = KEV_ANY_SUBCLASS;
471	if (ioctl(so, SIOCSKEVFILT, &kev_req) == -1) {
472		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("ioctl(, SIOCSKEVFILT, ) failed"));
473		(void)close(so);
474		return;
475	}
476
477	if (ioctl(so, FIONBIO, &yes) == -1) {
478		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("ioctl(, FIONBIO, ) failed"));
479		(void)close(so);
480		return;
481	}
482
483	/* Create a CFSocketRef for the PF_SYSTEM kernel event socket */
484	es = CFSocketCreateWithNative(NULL,
485				      so,
486				      kCFSocketReadCallBack,
487				      KernelEvent_notification,
488				      &es_context);
489
490	/* Create and add a run loop source for the event socket */
491	rls = CFSocketCreateRunLoopSource(NULL, es, -1);
492	CFRelease(es);
493
494	CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
495	CFRelease(rls);
496
497	return;
498}
499
500
501#pragma mark -
502#pragma mark Power Management Events
503
504
505static void
506power_notification(void *refcon, io_service_t service, natural_t messageType, void *messageArgument)
507{
508	switch (messageType) {
509		case kIOMessageCanDevicePowerOff :
510			SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
511			      CFSTR("%s IORegisterForSystemPower: can device power off?"),
512			      elapsed());
513			break;
514		case kIOMessageDeviceWillPowerOff :
515			SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
516			      CFSTR("%s IORegisterForSystemPower: device will power off"),
517			      elapsed());
518			break;
519		case kIOMessageDeviceWillNotPowerOff :
520			SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
521			      CFSTR("%s IORegisterForSystemPower: device will not power off"),
522			      elapsed());
523			break;
524		case kIOMessageDeviceHasPoweredOn :
525			SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
526			      CFSTR("%s IORegisterForSystemPower: device has powered on"),
527			      elapsed());
528			break;
529		case kIOMessageCanSystemPowerOff :
530			SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
531			      CFSTR("%s IORegisterForSystemPower: can system power off?"),
532			      elapsed());
533			break;
534		case kIOMessageSystemWillPowerOff :
535			SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
536			      CFSTR("%s IORegisterForSystemPower: system will power off"),
537			      elapsed());
538			break;
539		case kIOMessageSystemWillNotPowerOff :
540			SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
541			      CFSTR("%s IORegisterForSystemPower: system will not power off"),
542			      elapsed());
543			break;
544		case kIOMessageCanSystemSleep :
545			SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
546			      CFSTR("%s IORegisterForSystemPower: can system sleep?"),
547			      elapsed());
548			/*
549			 * Idle sleep is about to kick in, but applications have
550			 * a chance to allow sleep (by calling IOAllowPowerChange)
551			 * or to prevent sleep (by calling IOCancelPowerChange).
552			 */
553			IOAllowPowerChange(power, (long)messageArgument);
554			break;
555		case kIOMessageSystemWillSleep :
556			SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
557			      CFSTR("%s IORegisterForSystemPower: system will sleep"),
558			      elapsed());
559			IOAllowPowerChange(power, (long)messageArgument);
560			break;
561		case kIOMessageSystemWillNotSleep :
562			SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
563			      CFSTR("%s IORegisterForSystemPower: system will not sleep"),
564			      elapsed());
565			break;
566		case kIOMessageSystemHasPoweredOn :
567			SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
568			      CFSTR("%s IORegisterForSystemPower: system has powered on"),
569			      elapsed());
570			break;
571		case kIOMessageSystemWillRestart :
572			SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
573			      CFSTR("%s IORegisterForSystemPower: system will restart"),
574			      elapsed());
575			break;
576		case kIOMessageSystemWillPowerOn :
577			SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
578			      CFSTR("%s IORegisterForSystemPower: system will power on"),
579			      elapsed());
580			break;
581		default :
582			SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
583			      CFSTR("%s IORegisterForSystemPower: message=%08lx"),
584			      elapsed(),
585			      (long unsigned int)messageType);
586			break;
587	}
588
589	return;
590}
591
592
593static void
594add_power_notification()
595{
596	io_object_t		iterator;
597	IONotificationPortRef	notify;
598
599	power = IORegisterForSystemPower(0, &notify, power_notification, &iterator);
600	if (power == MACH_PORT_NULL) {
601		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("IORegisterForSystemPower() failed"));
602		return;
603	}
604
605	CFRunLoopAddSource(CFRunLoopGetCurrent(),
606			   IONotificationPortGetRunLoopSource(notify),
607			   kCFRunLoopCommonModes);
608
609	return;
610}
611
612
613#ifdef	kIOPMMessageSleepWakeUUIDChange
614static void
615wake_uuid_notification(void *refcon, io_service_t service, natural_t messageType, void *messageArgument)
616{
617	CFStringRef	wake_uuid	= NULL;
618
619	if (messageType == kIOPMMessageSleepWakeUUIDChange) {
620		if (messageArgument == kIOPMMessageSleepWakeUUIDSet) {
621			wake_uuid = IORegistryEntryCreateCFProperty(service, CFSTR(kIOPMSleepWakeUUIDKey), NULL, 0);
622		}
623
624		if (wake_uuid != NULL) {
625			char	uuid[256];
626
627			_SC_cfstring_to_cstring(wake_uuid, uuid, sizeof(uuid), kCFStringEncodingUTF8);
628			asl_set(log_msg, MSGTRACER_KEY_DOMAIN, MY_MSGTRACER_DOMAIN);
629			asl_set(log_msg, MSGTRACER_KEY_UUID  , uuid);
630
631			SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
632			      CFSTR("%s wake UUID notification: UUID set (%@)"),
633			      elapsed(),
634			      wake_uuid);
635
636			CFRelease(wake_uuid);
637		} else {
638			asl_unset(log_msg, MSGTRACER_KEY_DOMAIN);
639			asl_unset(log_msg, MSGTRACER_KEY_UUID);
640
641			SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
642			      CFSTR("%s wake UUID notification: UUID not set"),
643			      elapsed());
644		}
645	}
646
647	return;
648}
649
650
651static void
652add_wake_uuid_notification()
653{
654	kern_return_t		kr;
655	io_object_t		notification	= IO_OBJECT_NULL;
656	IONotificationPortRef	notifyPort;
657	io_service_t		service;
658
659	notifyPort = IONotificationPortCreate(kIOMasterPortDefault);
660	service = IORegistryEntryFromPath(kIOMasterPortDefault,
661					  kIOPowerPlane ":/IOPowerConnection/IOPMrootDomain");
662	kr = IOServiceAddInterestNotification(notifyPort,
663					      service,
664					      kIOGeneralInterest,
665					      wake_uuid_notification,
666					      NULL,			// refCon
667					      &notification);
668	if (kr != KERN_SUCCESS) {
669		SCLOG(NULL, NULL, ASL_LEVEL_ERR,
670		      CFSTR("IOServiceAddInterestNotification() failed, kr=0x%x"),
671		      kr);
672		return;
673	}
674
675	CFRunLoopAddSource(CFRunLoopGetCurrent(),
676			   IONotificationPortGetRunLoopSource(notifyPort),
677			   kCFRunLoopDefaultMode);
678
679	wake_uuid_notification(NULL,
680			       service,
681			       kIOPMMessageSleepWakeUUIDChange,
682			       kIOPMMessageSleepWakeUUIDSet);
683
684	return;
685}
686#endif	// kIOPMMessageSleepWakeUUIDChange
687
688
689#pragma mark -
690#pragma mark SCDynamicStore "network" Events
691
692
693static void
694NetworkChange_notification(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
695{
696	CFIndex			i;
697	CFIndex			nk;
698	CFMutableStringRef	str;
699
700	str = CFStringCreateMutable(NULL, 0);
701	CFStringAppendFormat(str,
702			     NULL,
703			     CFSTR("%s SCDynamicStore \"network\" notification"),
704			     elapsed());
705
706	nk = CFArrayGetCount(changedKeys);
707	for (i = 0; i < nk; i++) {
708		CFArrayRef	components;
709		CFStringRef	key;
710		CFIndex		nc;
711
712		key = CFArrayGetValueAtIndex(changedKeys, i);
713
714		components = CFStringCreateArrayBySeparatingStrings(NULL, key, CFSTR("/"));
715		if (components == NULL) {
716			CFStringAppendFormat(str, NULL, CFSTR("\n%@"), key);
717			continue;
718		}
719
720		nc = CFArrayGetCount(components);
721		switch (nc) {
722			case 5 : {
723				CFStringRef	entity_id;
724
725				entity_id  = CFArrayGetValueAtIndex(components, 4);
726				if (CFEqual(entity_id, kSCEntNetLink)) {
727					CFDictionaryRef	dict;
728					const char	*val	= "?";
729
730					dict = SCDynamicStoreCopyValue(store, key);
731					if (dict != NULL) {
732						CFBooleanRef	link;
733
734						link = CFDictionaryGetValue(dict, kSCPropNetLinkActive);
735						if (link != NULL) {
736							val = CFBooleanGetValue(link) ? "up" : "down";
737						}
738
739						CFRelease(dict);
740					}
741					CFStringAppendFormat(str, NULL, CFSTR("\n%@ (%s)"), key, val);
742				} else if (CFEqual(entity_id, kSCEntNetIPv4) ||
743					   CFEqual(entity_id, kSCEntNetIPv6) ||
744					   CFEqual(entity_id, kSCEntNetDNS)) {
745					CFDictionaryRef	dict;
746
747					dict = SCDynamicStoreCopyValue(store, key);
748					if (dict != NULL) {
749						CFStringRef	val;
750
751						val = _SCCopyDescription(dict, NULL);
752						CFStringAppendFormat(str, NULL, CFSTR("\n%@ : %@"), key, val);
753						CFRelease(val);
754						CFRelease(dict);
755					} else {
756						CFStringAppendFormat(str, NULL, CFSTR("\n%@ : removed"), key);
757					}
758				} else if (CFEqual(entity_id, kSCEntNetAirPort)) {
759					CFDictionaryRef	dict;
760
761					dict = SCDynamicStoreCopyValue(store, key);
762					if (dict != NULL) {
763						CFStringRef	ssid_str;
764
765						ssid_str = CFDictionaryGetValue(dict, CFSTR("SSID_STR"));
766						if (ssid_str != NULL) {
767							CFDataRef	bssid;
768
769							bssid = CFDictionaryGetValue(dict, CFSTR("BSSID"));
770							CFStringAppendFormat(str, NULL, CFSTR("\n%@ : SSID: %@ BSSID: %s"),
771									     key,
772									     ssid_str,
773									     (bssid != NULL) ? ether_ntoa((struct ether_addr *)CFDataGetBytePtr(bssid)) : "<unknown>");
774						} else {
775							CFStringAppendFormat(str, NULL, CFSTR("\n%@ : no SSID"), key);
776						}
777						CFRelease(dict);
778					} else {
779						CFStringAppendFormat(str, NULL, CFSTR("\n%@ : removed"), key);
780					}
781				} else if (CFEqual(entity_id, kSCEntNetService)) {
782					CFDictionaryRef	dict;
783					CFStringRef	rank	= kSCNetworkServicePrimaryRankDefault;
784
785					dict = SCDynamicStoreCopyValue(store, key);
786					if ((dict == NULL) ||
787					    !CFDictionaryGetValueIfPresent(dict,
788									   kSCPropNetServicePrimaryRank,
789									   (const void **)&rank)) {
790						rank = kSCNetworkServicePrimaryRankDefault;
791					}
792					CFStringAppendFormat(str, NULL, CFSTR("\n%@ : Rank = %@"), key, rank);
793					if (dict != NULL) CFRelease(dict);
794				} else {
795					CFStringAppendFormat(str, NULL, CFSTR("\n%@"), key);
796				}
797				break;
798			}
799
800			case 4 : {
801				static CFStringRef	rank_setup_prefix	= NULL;
802				static CFStringRef	rank_state_prefix	= NULL;
803
804				if (rank_setup_prefix == NULL) {
805					rank_setup_prefix = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
806													kSCDynamicStoreDomainSetup,
807													CFSTR(""),
808													NULL);
809					rank_state_prefix = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL,
810													kSCDynamicStoreDomainState,
811													CFSTR(""),
812													NULL);
813				}
814
815				if (CFStringHasPrefix(key, rank_setup_prefix) ||
816				    CFStringHasPrefix(key, rank_state_prefix)) {
817					CFDictionaryRef	dict;
818					CFStringRef	rank	= kSCNetworkServicePrimaryRankDefault;
819
820					dict = SCDynamicStoreCopyValue(store, key);
821					if ((dict == NULL) ||
822					    !CFDictionaryGetValueIfPresent(dict,
823									   kSCPropNetServicePrimaryRank,
824									   (const void **)&rank)) {
825						rank = kSCNetworkServicePrimaryRankDefault;
826					}
827					CFStringAppendFormat(str, NULL, CFSTR("\n%@ : Rank = %@"), key, rank);
828					if (dict != NULL) CFRelease(dict);
829				} else {
830					CFStringAppendFormat(str, NULL, CFSTR("\n%@"), key);
831				}
832				break;
833			}
834
835			case 2 :
836				if (CFEqual(CFArrayGetValueAtIndex(components, 1),
837					    CFSTR(kIOPMSystemPowerCapabilitiesKeySuffix))) {
838					CFNumberRef	num;
839
840					num = SCDynamicStoreCopyValue(store, key);
841					if (num != NULL) {
842						IOPMSystemPowerStateCapabilities	capabilities;
843
844						if (isA_CFNumber(num) &&
845						    CFNumberGetValue(num, kCFNumberSInt32Type, &capabilities)) {
846							CFStringAppendFormat(str, NULL, CFSTR("\n%@ (0x%x)"), key, capabilities);
847						}
848
849						CFRelease(num);
850					}
851				} else {
852					CFStringAppendFormat(str, NULL, CFSTR("\n%@"), key);
853				}
854				break;
855
856			default :
857				CFStringAppendFormat(str, NULL, CFSTR("\n%@"), key);
858				break;
859		}
860
861		CFRelease(components);
862	}
863
864	SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO, CFSTR("%@"), str);
865	CFRelease(str);
866	return;
867}
868
869
870static void
871add_NetworkChange_keys(CFMutableArrayRef	keys,
872		       CFMutableArrayRef	patterns,
873		       CFStringRef		entity,
874		       Boolean			doGlobal,
875		       Boolean			doService,
876		       Boolean			doInterface)
877{
878	CFStringRef	key;
879	CFStringRef	pattern;
880
881	if (doGlobal) {
882		key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainSetup, entity);
883		CFArrayAppendValue(keys, key);
884		CFRelease(key);
885
886		key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, entity);
887		CFArrayAppendValue(keys, key);
888		CFRelease(key);
889	}
890
891	if (doService) {
892		pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, entity);
893		CFArrayAppendValue(patterns, pattern);
894		CFRelease(pattern);
895
896		pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, entity);
897		CFArrayAppendValue(patterns, pattern);
898		CFRelease(pattern);
899	}
900
901	if (doInterface) {
902		pattern = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, entity);
903		CFArrayAppendValue(patterns, pattern);
904		CFRelease(pattern);
905	}
906
907	return;
908}
909
910
911static void
912add_NetworkChange_notification()
913{
914	CFStringRef		dns_key;
915	CFStringRef		key;
916	CFMutableArrayRef	keys;
917	Boolean			ok;
918	CFMutableArrayRef	patterns;
919	SCDynamicStoreRef	store;
920	CFRunLoopSourceRef	rls;
921
922	store = SCDynamicStoreCreate(NULL, CFSTR("Logger.bundle-NetworkChange"), NetworkChange_notification, NULL);
923	if (store == NULL) {
924		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreate() failed"));
925		return;
926	}
927
928	keys     = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
929	patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
930
931	// Interface list
932
933	key = SCDynamicStoreKeyCreateNetworkInterface(NULL, kSCDynamicStoreDomainState);
934	CFArrayAppendValue(keys, key);
935	CFRelease(key);
936
937	// IPv4
938
939	add_NetworkChange_keys(keys, patterns, kSCEntNetIPv4, TRUE, TRUE, TRUE);
940
941	// IPv6
942
943	add_NetworkChange_keys(keys, patterns, kSCEntNetIPv6, TRUE, TRUE, TRUE);
944
945	// PPP, VPN
946
947	add_NetworkChange_keys(keys, patterns, kSCEntNetPPP,   FALSE, TRUE, TRUE);
948	add_NetworkChange_keys(keys, patterns, kSCEntNetVPN,   FALSE, TRUE, TRUE);
949	add_NetworkChange_keys(keys, patterns, kSCEntNetL2TP,  FALSE, TRUE, TRUE);
950	add_NetworkChange_keys(keys, patterns, kSCEntNetPPTP,  FALSE, TRUE, TRUE);
951	add_NetworkChange_keys(keys, patterns, kSCEntNetIPSec, FALSE, TRUE, TRUE);
952
953	// Link
954
955	add_NetworkChange_keys(keys, patterns, kSCEntNetLink, FALSE, FALSE, TRUE);
956
957	// AirPort (e.g. BSSID)
958
959	add_NetworkChange_keys(keys, patterns, kSCEntNetAirPort, FALSE, FALSE, TRUE);
960
961	// DNS
962
963	add_NetworkChange_keys(keys, patterns, kSCEntNetDNS, TRUE, TRUE, TRUE);
964
965	dns_key = CFStringCreateWithCString(NULL,
966					    dns_configuration_notify_key(),
967					    kCFStringEncodingASCII);
968	key = CFStringCreateWithFormat(NULL, NULL, CFSTR("Notify:%@"), dns_key);
969	CFRelease(dns_key);
970	CFArrayAppendValue(keys, key);
971	CFRelease(key);
972
973	// Proxies
974
975	key = SCDynamicStoreKeyCreateProxies(NULL);
976	CFArrayAppendValue(keys, key);
977	CFRelease(key);
978
979	// Rank
980
981	add_NetworkChange_keys(keys, patterns, NULL, FALSE, TRUE, FALSE);		// per-service
982	add_NetworkChange_keys(keys, patterns, kSCEntNetService, FALSE, FALSE, TRUE);	// per-interface
983
984	// ComputerName, LocalHostName
985
986	key = SCDynamicStoreKeyCreateComputerName(NULL);
987	CFArrayAppendValue(keys, key);
988	CFRelease(key);
989
990	key = SCDynamicStoreKeyCreateHostNames(NULL);
991	CFArrayAppendValue(keys, key);
992	CFRelease(key);
993
994	// Power Management
995
996	key = SCDynamicStoreKeyCreate(NULL, CFSTR("%@%@"),
997				      kSCDynamicStoreDomainState,
998				      CFSTR(kIOPMSystemPowerCapabilitiesKeySuffix));
999	CFArrayAppendValue(keys, key);
1000	CFRelease(key);
1001
1002
1003	// Setup monitoring
1004
1005	ok = SCDynamicStoreSetNotificationKeys(store, keys, patterns);
1006	CFRelease(keys);
1007	CFRelease(patterns);
1008	if (!ok) {
1009		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreSetNotificationKeys() failed"));
1010		CFRelease(store);
1011		return;
1012	}
1013
1014	rls = SCDynamicStoreCreateRunLoopSource(NULL, store, -1);
1015	if (rls == NULL) {
1016		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
1017		CFRelease(store);
1018		return;
1019	}
1020	CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
1021	CFRelease(rls);
1022
1023	CFRelease(store);
1024	return;
1025}
1026
1027
1028static void
1029PrimaryService_notification(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
1030{
1031	CFDictionaryRef		entity;
1032	CFStringRef		key;
1033	static CFStringRef	oldPrimary	= NULL;
1034	CFStringRef		newPrimary	= NULL;
1035
1036	key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
1037	entity = SCDynamicStoreCopyValue(store, key);
1038	CFRelease(key);
1039	if (isA_CFDictionary(entity) &&
1040	    CFDictionaryGetValueIfPresent(entity,
1041					  kSCDynamicStorePropNetPrimaryService,
1042					  (const void **)&newPrimary) &&
1043	    isA_CFString(newPrimary)) {
1044		CFRetain(newPrimary);
1045	} else {
1046		newPrimary = NULL;
1047	}
1048
1049	if (!_SC_CFEqual(oldPrimary, newPrimary)) {
1050		if (newPrimary != NULL) {
1051			CFStringRef	newInterface;
1052
1053			newInterface = CFDictionaryGetValue(entity, kSCDynamicStorePropNetPrimaryInterface);
1054			SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
1055			      CFSTR("%s Primary service: %@ (%@)"),
1056			      elapsed(),
1057			      newPrimary,
1058			      newInterface != NULL ? newInterface : CFSTR("?"));
1059		} else {
1060			SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
1061			      CFSTR("%s Primary service: removed"),
1062			      elapsed());
1063		}
1064	}
1065
1066	if (oldPrimary != NULL) CFRelease(oldPrimary);
1067	oldPrimary = newPrimary;
1068
1069	if (entity != NULL)	CFRelease(entity);
1070	return;
1071}
1072
1073
1074static void
1075add_PrimaryService_notification()
1076{
1077	CFStringRef		key;
1078	CFMutableArrayRef	keys;
1079	Boolean			ok;
1080	SCDynamicStoreRef	store;
1081	CFRunLoopSourceRef	rls;
1082
1083	store = SCDynamicStoreCreate(NULL, CFSTR("Logger.bundle-PrimaryService"), PrimaryService_notification, NULL);
1084	if (store == NULL) {
1085		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreate() failed"));
1086		return;
1087	}
1088
1089	keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1090	key  = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
1091	CFArrayAppendValue(keys, key);
1092	CFRelease(key);
1093
1094	ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL);
1095	CFRelease(keys);
1096	if (!ok) {
1097		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreSetNotificationKeys() failed"));
1098		CFRelease(store);
1099		return;
1100	}
1101
1102	rls = SCDynamicStoreCreateRunLoopSource(NULL, store, -1);
1103	if (rls == NULL) {
1104		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
1105		CFRelease(store);
1106		return;
1107	}
1108	CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
1109	CFRelease(rls);
1110
1111	CFRelease(store);
1112	return;
1113}
1114
1115
1116#pragma mark -
1117#pragma mark Reachability Events
1118
1119
1120static void
1121reachability_notification(SCNetworkReachabilityRef ref, SCNetworkReachabilityFlags flags, void *info)
1122{
1123	CFStringRef	hostname	= (CFStringRef)info;
1124
1125	SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
1126	      CFSTR("%s reachability changed: %@: flags=0x%08x"),
1127	      elapsed(),
1128	      hostname,
1129	      flags);
1130	return;
1131}
1132
1133
1134static void
1135add_reachability_notification(CFArrayRef hosts)
1136{
1137	SCNetworkReachabilityContext	context	= { 0, NULL, CFRetain, CFRelease, CFCopyDescription };
1138	CFIndex				i;
1139	CFIndex				n;
1140	SCNetworkReachabilityRef	target;
1141
1142	struct watch {
1143		in_addr_t	addr;
1144		CFStringRef	name;
1145	} watchAddresses[]	= { { 0,			CFSTR("0.0.0.0")	},
1146				    { IN_LINKLOCALNETNUM,	CFSTR("169.254.0.0")	},
1147				    { (u_int32_t)0xe00000fb,	CFSTR("224.0.0.251")	},
1148				  };
1149
1150	for (i = 0; i < sizeof(watchAddresses)/sizeof(watchAddresses[0]); i++) {
1151		struct sockaddr_in		sin;
1152
1153		bzero(&sin, sizeof(sin));
1154		sin.sin_len    = sizeof(sin);
1155		sin.sin_family = AF_INET;
1156		sin.sin_addr.s_addr = htonl(watchAddresses[i].addr);
1157
1158		target = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&sin);
1159		if (target == NULL) {
1160			SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCNetworkReachabilityCreateWithAddress() failed"));
1161			return;
1162		}
1163
1164		context.info = (void *)watchAddresses[i].name;
1165		if (!SCNetworkReachabilitySetCallback(target, reachability_notification, &context)) {
1166			SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCNetworkReachabilitySetCallback() failed"));
1167			CFRelease(target);
1168			return;
1169		}
1170
1171		if (!SCNetworkReachabilityScheduleWithRunLoop(target, CFRunLoopGetCurrent(), kCFRunLoopCommonModes)) {
1172			SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCNetworkReachabilityScheduleWithRunLoop() failed"));
1173			CFRelease(target);
1174			return;
1175		}
1176
1177		CFRelease(target);
1178	}
1179
1180	n = (hosts != NULL) ? CFArrayGetCount(hosts) : 0;
1181	for (i = 0; i < n; i++) {
1182		CFStringRef	host;
1183		char		*nodename;
1184
1185		host = CFArrayGetValueAtIndex(hosts, i);
1186		if (!isA_CFString(host) || (CFStringGetLength(host) == 0)) {
1187			continue;
1188		}
1189
1190		nodename = _SC_cfstring_to_cstring(host, NULL, 0, kCFStringEncodingUTF8);
1191		target = SCNetworkReachabilityCreateWithName(NULL, nodename);
1192		CFAllocatorDeallocate(NULL, nodename);
1193		if (target == NULL) {
1194			SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCNetworkReachabilityCreateWithName() failed"));
1195			return;
1196		}
1197
1198		context.info = (void *)host;
1199		if (!SCNetworkReachabilitySetCallback(target, reachability_notification, &context)) {
1200			SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCNetworkReachabilitySetCallback() failed"));
1201			CFRelease(target);
1202			return;
1203		}
1204
1205		if (!SCNetworkReachabilityScheduleWithRunLoop(target, CFRunLoopGetCurrent(), kCFRunLoopCommonModes)) {
1206			SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCNetworkReachabilityScheduleWithRunLoop() failed"));
1207			CFRelease(target);
1208			return;
1209		}
1210
1211		CFRelease(target);
1212	}
1213
1214	return;
1215}
1216
1217
1218#pragma mark -
1219#pragma mark Console User/Information Events
1220
1221
1222#if	!TARGET_OS_EMBEDDED
1223static void
1224console_notification(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
1225{
1226	gid_t			gid;
1227	CFArrayRef		info;
1228	CFMutableStringRef	str	= CFStringCreateMutable(NULL, 0);
1229	uid_t			uid;
1230	CFStringRef		user;
1231
1232	CFStringAppendFormat(str,
1233			     NULL,
1234			     CFSTR("%s SCDynamicStore console notification"),
1235			     elapsed());
1236
1237	user = SCDynamicStoreCopyConsoleUser(store, &uid, &gid);
1238	if (user != NULL) {
1239		CFStringAppendFormat(str, NULL, CFSTR("\nconsole user = %@"), user);
1240		CFRelease(user);
1241	} else {
1242		CFStringAppendFormat(str, NULL, CFSTR("\nno console user"));
1243	}
1244
1245	info = SCDynamicStoreCopyConsoleInformation(store);
1246	if (info != NULL) {
1247		CFIndex		i;
1248		CFIndex		n;
1249
1250		n = CFArrayGetCount(info);
1251		for (i = 0; i < n; i++) {
1252			CFDictionaryRef	session;
1253			CFNumberRef	sessionID;
1254			CFStringRef	sessionUserName;
1255			CFBooleanRef	sessionOnConsole;
1256
1257			session          = CFArrayGetValueAtIndex(info, i);
1258			sessionID        = CFDictionaryGetValue(session, kSCConsoleSessionID);
1259			sessionUserName  = CFDictionaryGetValue(session, kSCConsoleSessionUserName);
1260			sessionOnConsole = CFDictionaryGetValue(session, kSCConsoleSessionOnConsole);
1261
1262			CFStringAppendFormat(str, NULL, CFSTR("\n%ld : id=%@, user=%@, console=%s"),
1263					     i,
1264					     sessionID,
1265					     sessionUserName  != NULL ? sessionUserName : CFSTR("?"),
1266					     sessionOnConsole != NULL ? CFBooleanGetValue(sessionOnConsole) ? "yes"  : "no" : "?");
1267		}
1268
1269		CFRelease(info);
1270	}
1271
1272	SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO, CFSTR("%@"), str);
1273	CFRelease(str);
1274	return;
1275}
1276
1277
1278static void
1279add_console_notification()
1280{
1281	CFStringRef		key;
1282	CFMutableArrayRef	keys;
1283	Boolean			ok;
1284	SCDynamicStoreRef	store;
1285	CFRunLoopSourceRef	rls;
1286
1287	store = SCDynamicStoreCreate(NULL, CFSTR("Logger.bundle-console"), console_notification, NULL);
1288	if (store == NULL) {
1289		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreate() failed"));
1290		return;
1291	}
1292
1293	keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1294
1295	key = SCDynamicStoreKeyCreateConsoleUser(NULL);
1296	CFArrayAppendValue(keys, key);
1297	CFRelease(key);
1298
1299	ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL);
1300	CFRelease(keys);
1301	if (!ok) {
1302		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreSetNotificationKeys() failed"));
1303		CFRelease(store);
1304		return;
1305	}
1306
1307	rls = SCDynamicStoreCreateRunLoopSource(NULL, store, -1);
1308	if (rls == NULL) {
1309		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
1310		CFRelease(store);
1311		return;
1312	}
1313	CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
1314	CFRelease(rls);
1315
1316	CFRelease(store);
1317	return;
1318}
1319#endif	// !TARGET_OS_EMBEDDED
1320
1321
1322#pragma mark -
1323#pragma mark Directory Services Events
1324
1325
1326//#include <DirectoryServices/DirServicesPriv.h>
1327#ifndef	kDSStdNotifySearchPolicyChanged
1328#define	kDSStdNotifySearchPolicyChanged	"com.apple.DirectoryService.NotifyTypeStandard:SearchPolicyChanged"
1329#endif
1330
1331
1332#if	!TARGET_OS_EMBEDDED
1333static void
1334directoryServices_notification(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
1335{
1336	CFIndex			i;
1337	CFIndex			n;
1338	CFMutableStringRef	str	= CFStringCreateMutable(NULL, 0);
1339
1340	CFStringAppendFormat(str,
1341			     NULL,
1342			     CFSTR("%s SCDynamicStore DirectoryServices notification"),
1343			     elapsed());
1344
1345	n = CFArrayGetCount(changedKeys);
1346	for (i = 0; i < n; i++) {
1347		CFStringRef	key;
1348
1349		key = CFArrayGetValueAtIndex(changedKeys, i);
1350		CFStringAppendFormat(str, NULL, CFSTR("\n%@"), key);
1351	}
1352
1353	SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO, CFSTR("%@"), str);
1354	CFRelease(str);
1355	return;
1356}
1357
1358
1359static void
1360add_DirectoryServices_notification()
1361{
1362	CFStringRef		key;
1363	CFMutableArrayRef	keys;
1364	Boolean			ok;
1365	SCDynamicStoreRef	store;
1366	CFRunLoopSourceRef	rls;
1367
1368	store = SCDynamicStoreCreate(NULL, CFSTR("Logger.bundle-directoryServices"), directoryServices_notification, NULL);
1369	if (store == NULL) {
1370		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreate() failed"));
1371		return;
1372	}
1373
1374	keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1375
1376	key = CFSTR(kDSStdNotifySearchPolicyChanged);
1377	CFArrayAppendValue(keys, key);
1378//	CFRelease(key);
1379
1380	ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL);
1381	CFRelease(keys);
1382	if (!ok) {
1383		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreSetNotificationKeys() failed"));
1384		CFRelease(store);
1385		return;
1386	}
1387
1388	rls = SCDynamicStoreCreateRunLoopSource(NULL, store, -1);
1389	if (rls == NULL) {
1390		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
1391		CFRelease(store);
1392		return;
1393	}
1394	CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
1395	CFRelease(rls);
1396
1397	CFRelease(store);
1398	return;
1399}
1400#endif	// !TARGET_OS_EMBEDDED
1401
1402
1403#pragma mark -
1404#pragma mark DNS Configuration Events
1405
1406
1407static void
1408dnsinfo_notification(CFMachPortRef port, void *msg, CFIndex size, void *info)
1409{
1410	SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
1411		CFSTR("%s dnsinfo notification"),
1412		elapsed());
1413
1414	return;
1415}
1416
1417
1418static void
1419add_dnsinfo_notification()
1420{
1421	const char		*key;
1422	CFMachPortRef		mp;
1423	mach_port_t		notify_port;
1424	int			notify_token;
1425	CFRunLoopSourceRef	rls;
1426	uint32_t		status;
1427
1428	key = dns_configuration_notify_key();
1429	status = notify_register_mach_port(key, &notify_port, 0, &notify_token);
1430	if (status != NOTIFY_STATUS_OK) {
1431		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("notify_register_mach_port() failed"));
1432		return;
1433	}
1434
1435	mp = _SC_CFMachPortCreateWithPort("Logger/dns_configuration", notify_port, dnsinfo_notification, NULL);
1436	if (mp == NULL) {
1437		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("CFMachPortCreateWithPort() failed"));
1438		(void)notify_cancel(notify_token);
1439		return;
1440	}
1441
1442	rls = CFMachPortCreateRunLoopSource(NULL, mp, -1);
1443	if (rls == NULL) {
1444		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
1445		CFRelease(mp);
1446		(void)notify_cancel(notify_token);
1447		return;
1448	}
1449	CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
1450	CFRelease(rls);
1451
1452	CFRelease(mp);
1453	return;
1454}
1455
1456
1457#pragma mark -
1458#pragma mark Network Information Events
1459
1460
1461static void
1462nwi_notification(CFMachPortRef port, void *msg, CFIndex size, void *info)
1463{
1464	SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
1465	      CFSTR("%s network_information notification"),
1466	      elapsed());
1467
1468	return;
1469}
1470
1471
1472static void
1473add_nwi_notification()
1474{
1475	const char		*key;
1476	CFMachPortRef		mp;
1477	mach_port_t		notify_port;
1478	int			notify_token;
1479	CFRunLoopSourceRef	rls;
1480	uint32_t		status;
1481
1482	key = nwi_state_get_notify_key();
1483	status = notify_register_mach_port(key, &notify_port, 0, &notify_token);
1484	if (status != NOTIFY_STATUS_OK) {
1485		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("notify_register_mach_port() failed"));
1486		return;
1487	}
1488
1489	mp = _SC_CFMachPortCreateWithPort("Logger/nwi", notify_port, nwi_notification, NULL);
1490	if (mp == NULL) {
1491		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("CFMachPortCreateWithPort() failed"));
1492		(void)notify_cancel(notify_token);
1493		return;
1494	}
1495
1496	rls = CFMachPortCreateRunLoopSource(NULL, mp, -1);
1497	if (rls == NULL) {
1498		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
1499		CFRelease(mp);
1500		(void)notify_cancel(notify_token);
1501		return;
1502	}
1503	CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
1504	CFRelease(rls);
1505
1506	CFRelease(mp);
1507	return;
1508}
1509
1510
1511#pragma mark -
1512#pragma mark Network Configuration Change Events
1513
1514
1515static void
1516network_notification(CFMachPortRef port, void *msg, CFIndex size, void *info)
1517{
1518	SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
1519	      CFSTR("%s network_change notification"),
1520	      elapsed());
1521
1522	return;
1523}
1524
1525
1526static void
1527add_network_notification()
1528{
1529	CFMachPortRef		mp;
1530	mach_port_t		notify_port;
1531	int			notify_token;
1532	CFRunLoopSourceRef	rls;
1533	uint32_t		status;
1534
1535	status = notify_register_mach_port(_SC_NOTIFY_NETWORK_CHANGE,
1536					   &notify_port,
1537					   0,
1538					   &notify_token);
1539	if (status != NOTIFY_STATUS_OK) {
1540		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("notify_register_mach_port() failed"));
1541		return;
1542	}
1543
1544	mp = _SC_CFMachPortCreateWithPort("Logger/network_change", notify_port, network_notification, NULL);
1545	if (mp == NULL) {
1546		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("CFMachPortCreateWithPort() failed"));
1547		(void)notify_cancel(notify_token);
1548		return;
1549	}
1550
1551	rls = CFMachPortCreateRunLoopSource(NULL, mp, -1);
1552	if (rls == NULL) {
1553		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
1554		CFRelease(mp);
1555		(void)notify_cancel(notify_token);
1556		return;
1557	}
1558	CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
1559	CFRelease(rls);
1560
1561	CFRelease(mp);
1562	return;
1563}
1564
1565
1566#pragma mark -
1567#pragma mark SMB Configuration Events
1568
1569
1570#define	SMBCONFIGURATION_NOTIFY_KEY	"com.apple.system.SystemConfiguration.smb_configuration"
1571
1572
1573#if	!TARGET_OS_EMBEDDED
1574static void
1575smbconf_notification(CFMachPortRef port, void *msg, CFIndex size, void *info)
1576{
1577	SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
1578	      CFSTR("%s smb.conf notification"),
1579	      elapsed());
1580
1581	return;
1582}
1583
1584
1585static void
1586add_smbconf_notification()
1587{
1588	CFMachPortRef		mp;
1589	mach_port_t		notify_port;
1590	int			notify_token;
1591	CFRunLoopSourceRef	rls;
1592	uint32_t		status;
1593
1594	status = notify_register_mach_port(SMBCONFIGURATION_NOTIFY_KEY,
1595					   &notify_port,
1596					   0,
1597					   &notify_token);
1598	if (status != NOTIFY_STATUS_OK) {
1599		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("notify_register_mach_port() failed"));
1600		return;
1601	}
1602
1603	mp = _SC_CFMachPortCreateWithPort("Logger/smb_configuration", notify_port, smbconf_notification, NULL);
1604	if (mp == NULL) {
1605		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("CFMachPortCreateWithPort() failed"));
1606		(void)notify_cancel(notify_token);
1607		return;
1608	}
1609
1610	rls = CFMachPortCreateRunLoopSource(NULL, mp, -1);
1611	if (rls == NULL) {
1612		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
1613		CFRelease(mp);
1614		(void)notify_cancel(notify_token);
1615		return;
1616	}
1617	CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
1618	CFRelease(rls);
1619
1620	CFRelease(mp);
1621	return;
1622}
1623#endif	// !TARGET_OS_EMBEDDED
1624
1625
1626#pragma mark -
1627#pragma mark pututxline Events
1628
1629
1630#ifndef	TARGET_OS_EMBEDDED
1631static const char *
1632ut_time(struct utmpx *utmpx)
1633{
1634	static char	str[16];
1635	struct tm	tm;
1636
1637	(void)localtime_r(&utmpx->ut_tv.tv_sec, &tm);
1638	snprintf(str, sizeof(str), "%2d:%02d:%02d.%03d",
1639		tm.tm_hour,
1640		tm.tm_min,
1641		tm.tm_sec,
1642		utmpx->ut_tv.tv_usec / 1000);
1643
1644	return str;
1645}
1646
1647
1648static const char *
1649ut_id(struct utmpx *utmpx)
1650{
1651	char		*cp;
1652	static char	str[16];
1653
1654	cp = utmpx->ut_id + sizeof(utmpx->ut_id);
1655	while(--cp >= utmpx->ut_id && isprint(*cp)) {}
1656	if(cp < utmpx->ut_id) {
1657		snprintf(str, sizeof(str), "%-4.4s", utmpx->ut_id);
1658	} else {
1659		snprintf(str, sizeof(str),
1660			 "0x%2.2x%2.2x%2.2x%2.2x",
1661			 utmpx->ut_id[0],
1662			 utmpx->ut_id[1],
1663			 utmpx->ut_id[2],
1664			 utmpx->ut_id[3]);
1665	}
1666
1667	return str;
1668}
1669
1670
1671static const char *
1672ut_pid(struct utmpx *utmpx)
1673{
1674	static char	pid[16];
1675
1676	snprintf(pid, sizeof(pid), "%d", utmpx->ut_pid);
1677
1678	return pid;
1679}
1680
1681
1682static void
1683pututxline_notification(CFMachPortRef port, void *msg, CFIndex size, void *info)
1684{
1685	CFMutableStringRef	str	= CFStringCreateMutable(NULL, 0);
1686	struct utmpx		*utmpx;
1687	utmpx_t			utx;
1688
1689	CFStringAppendFormat(str,
1690			     NULL,
1691			     CFSTR("%s pututxline notification"),
1692			     elapsed());
1693
1694	utx = _openutx(NULL);
1695	while ((utmpx = _getutxent(utx)) != NULL) {
1696		const char *	entry_id	= NULL;
1697		const char *	entry_line	= NULL;
1698		const char *	entry_pid	= NULL;
1699		const char *	entry_tv	= NULL;
1700		const char *	entry_type;
1701		const char *	entry_user	= NULL;
1702		char		line[128];
1703		int		n;
1704
1705		switch (utmpx->ut_type) {
1706			case BOOT_TIME :	// Time of a system boot.
1707				entry_type = "Boot";
1708				entry_tv   = ut_time(utmpx);
1709				break;
1710			case DEAD_PROCESS :	// A session leader exited.
1711				entry_type = "Dead process";
1712				entry_id   = ut_id  (utmpx);
1713				entry_pid  = ut_pid (utmpx);
1714				entry_tv   = ut_time(utmpx);
1715				break;
1716			case EMPTY :		// No valid user accounting information.
1717				continue;
1718			case INIT_PROCESS :	// A process spawned by init(8).
1719				entry_type = "Init process";
1720				entry_id   = ut_id  (utmpx);
1721				entry_pid  = ut_pid (utmpx);
1722				entry_tv   = ut_time(utmpx);
1723				break;
1724			case LOGIN_PROCESS :	// The session leader of a logged-in user.
1725				entry_type = "Login";
1726				entry_id   = ut_id  (utmpx);
1727				entry_user = utmpx->ut_user;
1728				entry_pid  = ut_pid (utmpx);
1729				entry_tv   = ut_time(utmpx);
1730				break;
1731			case NEW_TIME :		// Time after system clock change.
1732				entry_type = "New time";
1733				entry_tv   = ut_time(utmpx);
1734				break;
1735			case OLD_TIME :		// Time before system clock change.
1736				entry_type = "Old time";
1737				entry_tv   = ut_time(utmpx);
1738				break;
1739			case RUN_LVL :		// Run level.	Provided for compatibility, not used.
1740				entry_type = "Run level";
1741				break;
1742			case USER_PROCESS :	// A user process.
1743				entry_type = "User Process";
1744				entry_id   = ut_id  (utmpx);
1745				entry_user = utmpx->ut_user;
1746				entry_line = utmpx->ut_line;
1747				entry_pid  = ut_pid (utmpx);
1748				entry_tv   = ut_time(utmpx);
1749				break;
1750			case SHUTDOWN_TIME :	// Time of system shutdown
1751				entry_type = "Shutdown time";
1752				entry_tv   = ut_time(utmpx);
1753				break;
1754			default :
1755				entry_type = "Unknown";
1756				break;
1757		}
1758
1759		snprintf(line, sizeof(line),
1760			 // type  time    id=0x12345678 pid=12345 user=abcdefgh line
1761			 "\n%-13s %2s%12s %3s%-10s %4s%-5s %5s%-8s %5s%s",
1762			 entry_type,
1763			 entry_tv   != NULL ? "@ "       : "",
1764			 entry_tv   != NULL ? entry_tv   : "",	// hh:mm:ss.ddd
1765			 entry_id   != NULL ? "id="      : "",
1766			 entry_id   != NULL ? entry_id   : "",	// 0x12345678
1767			 entry_pid  != NULL ? "pid="     : "",
1768			 entry_pid  != NULL ? entry_pid  : "",	// #####
1769			 entry_user != NULL ? "user="    : "",
1770			 entry_user != NULL ? entry_user : "",	// <=256 chars
1771			 entry_line != NULL ? "line="    : "",
1772			 entry_line != NULL ? entry_line : ""	// <= 32 chars
1773			);
1774
1775		n = (int)strlen(line) - 1;
1776		while ((n > 0) && (line[n] == ' ')) {
1777			line[n] = '\0';
1778			--n;
1779		}
1780
1781		CFStringAppendFormat(str, NULL, CFSTR("%s"), line);
1782	}
1783	_endutxent(utx);
1784
1785	SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO, CFSTR("%@"), str);
1786	CFRelease(str);
1787	return;
1788}
1789
1790
1791static void
1792add_pututxline_notification()
1793{
1794	CFMachPortRef		mp;
1795	mach_port_t		notify_port;
1796	int			notify_token;
1797	CFRunLoopSourceRef	rls;
1798	uint32_t		status;
1799
1800	status = notify_register_mach_port(UTMPX_CHANGE_NOTIFICATION, &notify_port, 0, &notify_token);
1801	if (status != NOTIFY_STATUS_OK) {
1802		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("notify_register_mach_port() failed"));
1803		return;
1804	}
1805
1806	mp = _SC_CFMachPortCreateWithPort("Logger/utmpx", notify_port, pututxline_notification, NULL);
1807	if (mp == NULL) {
1808		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("CFMachPortCreateWithPort() failed"));
1809		(void)notify_cancel(notify_token);
1810		return;
1811	}
1812
1813	rls = CFMachPortCreateRunLoopSource(NULL, mp, -1);
1814	if (rls == NULL) {
1815		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
1816		CFRelease(mp);
1817		(void)notify_cancel(notify_token);
1818		return;
1819	}
1820	CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
1821	CFRelease(rls);
1822
1823	CFRelease(mp);
1824	return;
1825}
1826#endif	// !TARGET_OS_EMBEDDED
1827
1828
1829#pragma mark -
1830#pragma mark BackToMyMac Status Events
1831
1832
1833#ifndef	kDSStdNotifyBTMMStatusChanged
1834#define	kDSStdNotifyBTMMStatusChanged "State:/Network/BackToMyMac"
1835#endif
1836
1837
1838#if	!TARGET_OS_EMBEDDED
1839static void
1840BTMM_notification(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
1841{
1842	CFIndex			i;
1843	CFIndex			n;
1844	CFMutableStringRef	str	= CFStringCreateMutable(NULL, 0);
1845
1846	CFStringAppendFormat(str,
1847			     NULL,
1848			     CFSTR("%s SCDynamicStore Back to My Mac notification"),
1849			     elapsed());
1850
1851	n = CFArrayGetCount(changedKeys);
1852	for (i = 0; i < n; i++) {
1853		CFStringRef	key;
1854		CFDictionaryRef	dict;
1855
1856		key = CFArrayGetValueAtIndex(changedKeys, i);
1857		dict = SCDynamicStoreCopyValue(store, key);
1858		if (dict != NULL) {
1859			CFStringRef	val;
1860
1861			val = _SCCopyDescription(dict, NULL);
1862			CFStringAppendFormat(str, NULL, CFSTR("\n%@ : %@"), key, val);
1863			CFRelease(val);
1864			CFRelease(dict);
1865		} else {
1866			CFStringAppendFormat(str, NULL, CFSTR("\n%@ : removed"), key);
1867		}
1868	}
1869
1870	SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO, CFSTR("%@"), str);
1871	CFRelease(str);
1872	return;
1873}
1874
1875
1876static void
1877add_BTMM_notification()
1878{
1879	CFStringRef		key;
1880	CFMutableArrayRef	keys;
1881	Boolean			ok;
1882	SCDynamicStoreRef	store;
1883	CFRunLoopSourceRef	rls;
1884
1885	store = SCDynamicStoreCreate(NULL, CFSTR("Logger.bundle-BackToMyMac"), BTMM_notification, NULL);
1886	if (store == NULL) {
1887		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreate() failed"));
1888		return;
1889	}
1890
1891	keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
1892
1893	key = CFSTR(kDSStdNotifyBTMMStatusChanged);
1894	CFArrayAppendValue(keys, key);
1895
1896	ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL);
1897	CFRelease(keys);
1898	if (!ok) {
1899		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreSetNotificationKeys() failed"));
1900		CFRelease(store);
1901		return;
1902	}
1903
1904	rls = SCDynamicStoreCreateRunLoopSource(NULL, store, -1);
1905	if (rls == NULL) {
1906		SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
1907		CFRelease(store);
1908		return;
1909	}
1910	CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
1911	CFRelease(rls);
1912
1913	CFRelease(store);
1914	return;
1915}
1916#endif	// !TARGET_OS_EMBEDDED
1917
1918
1919#pragma mark -
1920
1921
1922static __inline__ Boolean
1923bValFromDictionary(CFDictionaryRef dict, CFStringRef key)
1924{
1925	CFBooleanRef	bVal;
1926	Boolean		result	= FALSE;
1927
1928	if ((dict != NULL) &&
1929	    CFDictionaryGetValueIfPresent(dict, key, (const void **)&bVal) &&
1930	    isA_CFBoolean(bVal)) {
1931		result = CFBooleanGetValue(bVal);
1932	}
1933
1934	return result;
1935}
1936
1937
1938void
1939load(CFBundleRef bundle, Boolean bundleVerbose)
1940{
1941	CFDictionaryRef	config;
1942	Boolean		log_all;
1943
1944	verbose = bundleVerbose;
1945
1946	log_msg = asl_new(ASL_TYPE_MSG);
1947	asl_set(log_msg, ASL_KEY_FACILITY, MY_ASL_FACILITY);
1948
1949	elapsed();
1950
1951	config = CFBundleGetInfoDictionary(bundle);
1952	config = isA_CFDictionary(config);
1953	log_all = bValFromDictionary(config, CFSTR("LOG_ALL"));
1954
1955#ifdef	kIOPMMessageSleepWakeUUIDChange
1956	if (log_all || bValFromDictionary(config, CFSTR("LOG_IO_WAKEUUID_EVENTS"))) {
1957		add_wake_uuid_notification();
1958	}
1959#endif	// kIOPMMessageSleepWakeUUIDChange
1960
1961	if (log_all || bValFromDictionary(config, CFSTR("LOG_IO_SYSTEMPOWER_EVENTS"))) {
1962		add_power_notification();
1963	}
1964
1965	if (log_all || bValFromDictionary(config, CFSTR("LOG_NETWORK_KERNEL_EVENTS"))) {
1966		add_KernelEvent_notification();
1967	}
1968
1969	if (log_all || bValFromDictionary(config, CFSTR("LOG_NETWORK_INFORMATION"))) {
1970		add_nwi_notification();
1971	}
1972
1973	if (log_all || bValFromDictionary(config, CFSTR("LOG_NOTIFY_DNS_CONFIGURATION"))) {
1974		add_dnsinfo_notification();
1975	}
1976
1977	if (log_all || bValFromDictionary(config, CFSTR("LOG_NOTIFY_NETWORK_CHANGE"))) {
1978		add_network_notification();
1979	}
1980
1981#if	!TARGET_OS_EMBEDDED
1982	if (log_all || bValFromDictionary(config, CFSTR("LOG_NOTIFY_SMB_CONFIGURATION"))) {
1983		add_smbconf_notification();
1984	}
1985#endif	// !TARGET_OS_EMBEDDED
1986
1987#ifndef	TARGET_OS_EMBEDDED
1988	if (log_all || bValFromDictionary(config, CFSTR("LOG_NOTIFY_UTMPX_CHANGE"))) {
1989		add_pututxline_notification();
1990	}
1991#endif	// !TARGET_OS_EMBEDDED
1992
1993#if	!TARGET_OS_EMBEDDED
1994	if (log_all || bValFromDictionary(config, CFSTR("LOG_SC_BTMM_CONFIGURATION"))) {
1995		add_BTMM_notification();
1996	}
1997#endif	// !TARGET_OS_EMBEDDED
1998
1999#if	!TARGET_OS_EMBEDDED
2000	if (log_all || bValFromDictionary(config, CFSTR("LOG_SC_CONSOLEUSER"))) {
2001		add_console_notification();
2002	}
2003#endif	// !TARGET_OS_EMBEDDED
2004
2005#if	!TARGET_OS_EMBEDDED
2006	if (log_all || bValFromDictionary(config, CFSTR("LOG_SC_DIRECTORYSERVICES_SEARCHPOLICY"))) {
2007		add_DirectoryServices_notification();
2008	}
2009#endif	// !TARGET_OS_EMBEDDED
2010
2011	if (log_all || bValFromDictionary(config, CFSTR("LOG_SC_NETWORKCHANGE"))) {
2012		add_NetworkChange_notification();
2013	}
2014
2015	if (log_all || bValFromDictionary(config, CFSTR("LOG_SC_PRIMARYSERVICE"))) {
2016		add_PrimaryService_notification();
2017	}
2018
2019	if (log_all || bValFromDictionary(config, CFSTR("LOG_SC_REACHABILITY"))) {
2020		CFArrayRef	hosts	= NULL;
2021
2022		if ((config == NULL) ||
2023		    !CFDictionaryGetValueIfPresent(config, CFSTR("LOG_SC_REACHABILITY_HOSTS"), (const void **)&hosts) ||
2024		    !isA_CFArray(hosts) ||
2025		    (CFArrayGetCount(hosts) == 0)) {
2026			hosts = NULL;
2027		}
2028
2029		if (verbose) {
2030			_sc_debug = TRUE;
2031		}
2032
2033		add_reachability_notification(hosts);
2034	}
2035
2036	return;
2037}
2038
2039#ifdef	MAIN
2040
2041int
2042main(int argc, char **argv)
2043{
2044	_sc_log     = FALSE;
2045	_sc_verbose = (argc > 1) ? TRUE : FALSE;
2046	_sc_debug   = TRUE;
2047
2048	load(CFBundleGetMainBundle(), (argc > 1) ? TRUE : FALSE);
2049	CFRunLoopRun();
2050	/* not reached */
2051	exit(0);
2052	return 0;
2053}
2054
2055#endif	/* MAIN */
2056