#include <stdlib.h>
#include <unistd.h>
#include <sys/filio.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_media.h>
#include <net/if_types.h>
#include <net/if_var.h>
#include <sys/kern_event.h>
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <netinet6/in6_var.h>
#include <ifaddrs.h>
#include <arpa/inet.h>
#include <TargetConditionals.h>
#include <CoreFoundation/CoreFoundation.h>
#include <SystemConfiguration/SystemConfiguration.h>
#include <SystemConfiguration/SCPrivate.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/IOMessage.h>
#include <IOKit/pwr_mgt/IOPM.h>
#include <IOKit/pwr_mgt/IOPMLib.h>
#include <dnsinfo.h>
#include <notify.h>
#include <utmpx.h>
#define MSGTRACER_KEY_DOMAIN "com.apple.message.domain"
#define MSGTRACER_KEY_SIG "com.apple.message.signature"
#define MSGTRACER_KEY_UUID "com.apple.message.uuid"
#define MSGTRACER_KEY_VALUE1 "com.apple.message.value"
#define MY_ASL_FACILITY "com.apple.SystemConfiguration.Logger"
#define MY_MSGTRACER_DOMAIN "com.apple.network.log"
static aslmsg log_msg = NULL;
static io_connect_t power = MACH_PORT_NULL;
static Boolean verbose = FALSE;
static char *
elapsed()
{
static char str[128];
struct tm tm_diff;
struct tm tm_now;
struct timeval tv_diff;
struct timeval tv_now;
static struct timeval tv_then = { 0, 0 };
(void)gettimeofday(&tv_now, NULL);
(void)localtime_r(&tv_now.tv_sec, &tm_now);
timersub(&tv_now, &tv_then, &tv_diff);
(void)localtime_r(&tv_diff.tv_sec, &tm_diff);
#ifdef MAIN
sprintf(str, "%2d:%02d:%02d.%03d (+%ld.%03d)",
tm_now.tm_hour,
tm_now.tm_min,
tm_now.tm_sec,
tv_now.tv_usec / 1000,
tv_diff.tv_sec,
tv_diff.tv_usec / 1000);
#else
sprintf(str, ".%03d (+%ld.%03d)",
tv_now.tv_usec / 1000,
tv_diff.tv_sec,
tv_diff.tv_usec / 1000);
#endif
tv_then = tv_now;
return str;
}
#pragma mark -
#pragma mark [Network] Kernel Events
static CFStringRef
copyInterfaceFlags(const char *if_name)
{
const char * iff_up = "? ";
struct ifreq ifr;
const char *ifm_active = "? ";
int sock;
CFStringRef str = NULL;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == -1) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("socket() failed"));
return NULL;
}
bzero((char *)&ifr, sizeof(ifr));
(void) strncpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
if (ioctl(sock, SIOCGIFFLAGS, (caddr_t)&ifr) == 0) {
struct ifmediareq ifm;
iff_up = (ifr.ifr_flags & IFF_UP) ? "yes" : "no ";
bzero((char *)&ifm, sizeof(ifm));
(void) strncpy(ifm.ifm_name, if_name, sizeof(ifm.ifm_name));
if ((ioctl(sock, SIOCGIFMEDIA, (caddr_t)&ifm) == 0) &&
(ifm.ifm_count > 0) &&
(ifm.ifm_status & IFM_AVALID)) {
ifm_active = (ifm.ifm_status & IFM_ACTIVE) ? "yes" : "no ";
}
str = CFStringCreateWithFormat(NULL,
NULL,
CFSTR("\n%-5s: IFF_UP = %s IFM_ACTIVE = %s"),
if_name,
iff_up,
ifm_active);
}
(void)close(sock);
return str;
}
static int
prefixLength(struct sockaddr_in6 *sin6)
{
register u_int8_t *name = &sin6->sin6_addr.s6_addr[0];
register int byte;
register int bit;
int plen = 0;
for (byte = 0; byte < sizeof(struct in6_addr); byte++, plen += 8) {
if (name[byte] != 0xff) {
break;
}
}
if (byte == sizeof(struct in6_addr)) {
return plen;
}
for (bit = 7; bit != 0; bit--, plen++) {
if (!(name[byte] & (1 << bit))) {
break;
}
}
for (; bit != 0; bit--) {
if (name[byte] & (1 << bit)) {
return 0;
}
}
byte++;
for (; byte < sizeof(struct in6_addr); byte++) {
if (name[byte]) {
return 0;
}
}
return plen;
}
static void
KernelEvent_notification(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(NULL, NULL, ASL_LEVEL_ERR, CFSTR("recv() failed: %s"), strerror(errno));
CFSocketInvalidate(s);
return;
}
while (offset < status) {
if ((offset + ev_msg->total_size) > status) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, 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 : {
void *event_data = &ev_msg->event_data[0];
switch (ev_msg->kev_subclass) {
case KEV_DL_SUBCLASS : {
struct net_event_data *ev;
char if_name[IFNAMSIZ+1];
ev = (struct net_event_data *)event_data;
bzero(&if_name, sizeof(if_name));
snprintf(if_name, IFNAMSIZ, "%s%d",
ev->if_name,
ev->if_unit);
switch (ev_msg->event_code) {
case KEV_DL_IF_ATTACHED : {
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
CFSTR("%s kernel event: %s: attached"),
elapsed(),
if_name);
break;
}
case KEV_DL_IF_DETACHING : {
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
CFSTR("%s kernel event: %s: detaching"),
elapsed(),
if_name);
break;
}
case KEV_DL_IF_DETACHED : {
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
CFSTR("%s kernel event: %s: detached"),
elapsed(),
if_name);
break;
}
case KEV_DL_LINK_OFF : {
CFStringRef str;
str = verbose ? copyInterfaceFlags(if_name) : NULL;
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
CFSTR("%s kernel event: %s: link down%@"),
elapsed(),
if_name,
str != NULL ? str : CFSTR(""));
if (str != NULL) CFRelease(str);
break;
}
case KEV_DL_LINK_ON : {
CFStringRef str;
str = verbose ? copyInterfaceFlags(if_name) : NULL;
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
CFSTR("%s kernel event: %s: link up%@"),
elapsed(),
if_name,
str != NULL ? str : CFSTR(""));
if (str != NULL) CFRelease(str);
break;
}
default :
break;
}
break;
}
case KEV_INET_SUBCLASS : {
char addr[128];
struct kev_in_data *ev;
char if_name[IFNAMSIZ+1];
char mask[128];
ev = (struct kev_in_data *)event_data;
bzero(&if_name, sizeof(if_name));
snprintf(if_name, IFNAMSIZ, "%s%d",
ev->link_data.if_name,
ev->link_data.if_unit);
switch (ev_msg->event_code) {
case KEV_INET_NEW_ADDR :
case KEV_INET_CHANGED_ADDR :
case KEV_INET_ADDR_DELETED : {
struct sockaddr_in sin;
bzero(&sin, sizeof(sin));
sin.sin_len = sizeof(sin);
sin.sin_family = AF_INET;
sin.sin_addr = ev->ia_addr;
_SC_sockaddr_to_string((struct sockaddr *)&sin, addr, sizeof(addr));
bzero(&sin, sizeof(sin));
sin.sin_len = sizeof(sin);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = ntohl(ev->ia_subnetmask);
_SC_sockaddr_to_string((struct sockaddr *)&sin, mask, sizeof(mask));
break;
}
default :
break;
}
switch (ev_msg->event_code) {
case KEV_INET_NEW_ADDR : {
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
CFSTR("%s kernel event: %s: IPv4 address added (%s/%s)"),
elapsed(),
if_name,
addr,
mask);
break;
}
case KEV_INET_CHANGED_ADDR : {
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
CFSTR("%s kernel event: %s: IPv4 address changed (%s/%s)"),
elapsed(),
if_name,
addr,
mask);
break;
}
case KEV_INET_ADDR_DELETED : {
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
CFSTR("%s kernel event: %s: IPv4 address removed (%s/%s)"),
elapsed(),
if_name,
addr,
mask);
break;
}
default :
break;
}
break;
}
case KEV_INET6_SUBCLASS : {
char addr[128];
struct kev_in6_data *ev;
char if_name[IFNAMSIZ+1];
int plen = 0;
ev = (struct kev_in6_data *)event_data;
bzero(&if_name, sizeof(if_name));
snprintf(if_name, IFNAMSIZ, "%s%d",
ev->link_data.if_name,
ev->link_data.if_unit);
switch (ev_msg->event_code) {
case KEV_INET6_NEW_USER_ADDR :
case KEV_INET6_NEW_LL_ADDR :
case KEV_INET6_CHANGED_ADDR :
case KEV_INET6_ADDR_DELETED : {
_SC_sockaddr_to_string((struct sockaddr *)&ev->ia_addr, addr, sizeof(addr));
plen = prefixLength(&ev->ia_prefixmask);
break;
}
default :
break;
}
switch (ev_msg->event_code) {
case KEV_INET6_NEW_USER_ADDR :
case KEV_INET6_NEW_LL_ADDR : {
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
CFSTR("%s kernel event: %s: IPv6 address added (%s/%d)"),
elapsed(),
if_name,
addr,
plen);
break;
}
case KEV_INET6_CHANGED_ADDR : {
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
CFSTR("%s kernel event: %s: IPv6 address changed (%s/%d)"),
elapsed(),
if_name,
addr,
plen);
break;
}
case KEV_INET6_ADDR_DELETED : {
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
CFSTR("%s kernel event: %s: IPv6 address removed"),
elapsed(),
if_name);
break;
}
default :
break;
}
break;
}
default :
break;
}
break;
}
default :
break;
}
break;
default :
break;
}
offset += ev_msg->total_size;
ev_msg = (struct kern_event_msg *)&buf[offset];
}
return;
}
static void
add_KernelEvent_notification()
{
CFSocketRef es;
CFSocketContext es_context = { 0, NULL, NULL, NULL, NULL };
struct kev_request kev_req;
CFRunLoopSourceRef rls;
int so;
int yes = 1;
so = socket(PF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT);
if (so == -1) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("socket() failed"));
return;
}
kev_req.vendor_code = 0;
kev_req.kev_class = 0;
kev_req.kev_subclass = 0;
if (ioctl(so, SIOCSKEVFILT, &kev_req) == -1) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("ioctl(, SIOCSKEVFILT, ) failed"));
(void)close(so);
return;
}
if (ioctl(so, FIONBIO, &yes) == -1) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("ioctl(, FIONBIO, ) failed"));
(void)close(so);
return;
}
es = CFSocketCreateWithNative(NULL,
so,
kCFSocketReadCallBack,
KernelEvent_notification,
&es_context);
rls = CFSocketCreateRunLoopSource(NULL, es, -1);
CFRelease(es);
CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
CFRelease(rls);
return;
}
#pragma mark -
#pragma mark Power Management Events
static void
power_notification(void *refcon, io_service_t service, natural_t messageType, void *messageArgument)
{
switch (messageType) {
case kIOMessageCanDevicePowerOff :
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
CFSTR("%s IORegisterForSystemPower: can device power off?"),
elapsed());
break;
case kIOMessageDeviceWillPowerOff :
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
CFSTR("%s IORegisterForSystemPower: device will power off"),
elapsed());
break;
case kIOMessageDeviceWillNotPowerOff :
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
CFSTR("%s IORegisterForSystemPower: device will not power off"),
elapsed());
break;
case kIOMessageDeviceHasPoweredOn :
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
CFSTR("%s IORegisterForSystemPower: device has powered on"),
elapsed());
break;
case kIOMessageCanSystemPowerOff :
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
CFSTR("%s IORegisterForSystemPower: can system power off?"),
elapsed());
break;
case kIOMessageSystemWillPowerOff :
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
CFSTR("%s IORegisterForSystemPower: system will power off"),
elapsed());
break;
case kIOMessageSystemWillNotPowerOff :
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
CFSTR("%s IORegisterForSystemPower: system will not power off"),
elapsed());
break;
case kIOMessageCanSystemSleep :
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
CFSTR("%s IORegisterForSystemPower: can system sleep?"),
elapsed());
IOAllowPowerChange(power, (long)messageArgument);
break;
case kIOMessageSystemWillSleep :
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
CFSTR("%s IORegisterForSystemPower: system will sleep"),
elapsed());
IOAllowPowerChange(power, (long)messageArgument);
break;
case kIOMessageSystemWillNotSleep :
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
CFSTR("%s IORegisterForSystemPower: system will not sleep"),
elapsed());
break;
case kIOMessageSystemHasPoweredOn :
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
CFSTR("%s IORegisterForSystemPower: system has powered on"),
elapsed());
break;
case kIOMessageSystemWillRestart :
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
CFSTR("%s IORegisterForSystemPower: system will restart"),
elapsed());
break;
case kIOMessageSystemWillPowerOn :
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
CFSTR("%s IORegisterForSystemPower: system will power on"),
elapsed());
break;
default :
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
CFSTR("%s IORegisterForSystemPower: message=%08lx"),
elapsed(),
(long unsigned int)messageType);
break;
}
return;
}
static void
add_power_notification()
{
io_object_t iterator;
IONotificationPortRef notify;
power = IORegisterForSystemPower(0, ¬ify, power_notification, &iterator);
if (power == MACH_PORT_NULL) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("IORegisterForSystemPower() failed"));
return;
}
CFRunLoopAddSource(CFRunLoopGetCurrent(),
IONotificationPortGetRunLoopSource(notify),
kCFRunLoopCommonModes);
return;
}
#ifdef kIOPMMessageSleepWakeUUIDChange
static void
wake_uuid_notification(void *refcon, io_service_t service, natural_t messageType, void *messageArgument)
{
CFStringRef wake_uuid = NULL;
if (messageType == kIOPMMessageSleepWakeUUIDChange) {
if (messageArgument == kIOPMMessageSleepWakeUUIDSet) {
wake_uuid = IORegistryEntryCreateCFProperty(service, CFSTR(kIOPMSleepWakeUUIDKey), NULL, 0);
}
if (wake_uuid != NULL) {
char uuid[256];
_SC_cfstring_to_cstring(wake_uuid, uuid, sizeof(uuid), kCFStringEncodingUTF8);
asl_set(log_msg, MSGTRACER_KEY_DOMAIN, MY_MSGTRACER_DOMAIN);
asl_set(log_msg, MSGTRACER_KEY_UUID , uuid);
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
CFSTR("%s wake UUID notification: UUID set (%@)"),
elapsed(),
wake_uuid);
CFRelease(wake_uuid);
} else {
asl_unset(log_msg, MSGTRACER_KEY_DOMAIN);
asl_unset(log_msg, MSGTRACER_KEY_UUID);
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
CFSTR("%s wake UUID notification: UUID not set"),
elapsed());
}
}
return;
}
static void
add_wake_uuid_notification()
{
kern_return_t kr;
io_object_t notification = IO_OBJECT_NULL;
IONotificationPortRef notifyPort;
io_service_t service;
notifyPort = IONotificationPortCreate(kIOMasterPortDefault);
service = IORegistryEntryFromPath(kIOMasterPortDefault,
kIOPowerPlane ":/IOPowerConnection/IOPMrootDomain");
kr = IOServiceAddInterestNotification(notifyPort,
service,
kIOGeneralInterest,
wake_uuid_notification,
NULL, ¬ification);
if (kr != KERN_SUCCESS) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR,
CFSTR("IOServiceAddInterestNotification() failed, kr=0x%x"),
kr);
return;
}
CFRunLoopAddSource(CFRunLoopGetCurrent(),
IONotificationPortGetRunLoopSource(notifyPort),
kCFRunLoopDefaultMode);
wake_uuid_notification(NULL,
service,
kIOPMMessageSleepWakeUUIDChange,
kIOPMMessageSleepWakeUUIDSet);
return;
}
#endif // kIOPMMessageSleepWakeUUIDChange
#pragma mark -
#pragma mark SCDynamicStore "network" Events
static void
NetworkChange_notification(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
{
CFIndex i;
CFIndex n;
CFMutableStringRef str = CFStringCreateMutable(NULL, 0);
CFStringAppendFormat(str,
NULL,
CFSTR("%s SCDynamicStore \"network\" notification"),
elapsed());
n = CFArrayGetCount(changedKeys);
for (i = 0; i < n; i++) {
CFStringRef key;
key = CFArrayGetValueAtIndex(changedKeys, i);
if (CFStringHasSuffix(key, kSCEntNetLink)) {
CFDictionaryRef dict;
const char *val = "?";
dict = SCDynamicStoreCopyValue(store, key);
if (dict != NULL) {
CFBooleanRef link;
link = CFDictionaryGetValue(dict, kSCPropNetLinkActive);
if (link != NULL) {
val = CFBooleanGetValue(link) ? "up" : "down";
}
CFRelease(dict);
}
CFStringAppendFormat(str, NULL, CFSTR("\n%@ (%s)"), key, val);
} else if (CFStringHasSuffix(key, kSCEntNetIPv4) ||
CFStringHasSuffix(key, kSCEntNetIPv6)) {
CFDictionaryRef dict;
dict = SCDynamicStoreCopyValue(store, key);
if (dict != NULL) {
CFStringRef val;
val = _SCCopyDescription(dict, NULL);
CFStringAppendFormat(str, NULL, CFSTR("\n%@ : %@"), key, val);
CFRelease(val);
CFRelease(dict);
} else {
CFStringAppendFormat(str, NULL, CFSTR("\n%@ : removed"), key);
}
} else {
CFStringAppendFormat(str, NULL, CFSTR("\n%@"), key);
}
}
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO, CFSTR("%@"), str);
CFRelease(str);
return;
}
static void
add_NetworkChange_notification()
{
CFStringRef dns_key;
CFStringRef key;
CFMutableArrayRef keys;
Boolean ok;
CFStringRef pattern;
CFMutableArrayRef patterns;
SCDynamicStoreRef store;
CFRunLoopSourceRef rls;
store = SCDynamicStoreCreate(NULL, CFSTR("Logger.bundle-NetworkChange"), NetworkChange_notification, NULL);
if (store == NULL) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreate() failed"));
return;
}
keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
key = SCDynamicStoreKeyCreateNetworkInterface(NULL, kSCDynamicStoreDomainState);
CFArrayAppendValue(keys, key);
CFRelease(key);
key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
CFArrayAppendValue(keys, key);
CFRelease(key);
pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4);
CFArrayAppendValue(patterns, pattern);
CFRelease(pattern);
pattern = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4);
CFArrayAppendValue(patterns, pattern);
CFRelease(pattern);
key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6);
CFArrayAppendValue(keys, key);
CFRelease(key);
pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6);
CFArrayAppendValue(patterns, pattern);
CFRelease(pattern);
pattern = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6);
CFArrayAppendValue(patterns, pattern);
CFRelease(pattern);
pattern = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetLink);
CFArrayAppendValue(patterns, pattern);
CFRelease(pattern);
pattern = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetAirPort);
CFArrayAppendValue(patterns, pattern);
CFRelease(pattern);
key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS);
CFArrayAppendValue(keys, key);
CFRelease(key);
dns_key = CFStringCreateWithCString(NULL,
dns_configuration_notify_key(),
kCFStringEncodingASCII);
key = CFStringCreateWithFormat(NULL, NULL, CFSTR("Notify:%@"), dns_key);
CFRelease(dns_key);
CFArrayAppendValue(keys, key);
CFRelease(key);
key = SCDynamicStoreKeyCreateProxies(NULL);
CFArrayAppendValue(keys, key);
CFRelease(key);
key = SCDynamicStoreKeyCreateComputerName(NULL);
CFArrayAppendValue(keys, key);
CFRelease(key);
key = SCDynamicStoreKeyCreateHostNames(NULL);
CFArrayAppendValue(keys, key);
CFRelease(key);
ok = SCDynamicStoreSetNotificationKeys(store, keys, patterns);
CFRelease(keys);
CFRelease(patterns);
if (!ok) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreSetNotificationKeys() failed"));
CFRelease(store);
return;
}
rls = SCDynamicStoreCreateRunLoopSource(NULL, store, -1);
if (rls == NULL) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
CFRelease(store);
return;
}
CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
CFRelease(rls);
CFRelease(store);
return;
}
static void
PrimaryService_notification(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
{
CFDictionaryRef entity;
CFStringRef key;
static CFStringRef oldPrimary = NULL;
CFStringRef newPrimary = NULL;
key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
entity = SCDynamicStoreCopyValue(store, key);
CFRelease(key);
if (isA_CFDictionary(entity) &&
CFDictionaryGetValueIfPresent(entity,
kSCDynamicStorePropNetPrimaryService,
(const void **)&newPrimary) &&
isA_CFString(newPrimary)) {
CFRetain(newPrimary);
} else {
newPrimary = NULL;
}
if (!_SC_CFEqual(oldPrimary, newPrimary)) {
if (newPrimary != NULL) {
CFStringRef newInterface;
newInterface = CFDictionaryGetValue(entity, kSCDynamicStorePropNetPrimaryInterface);
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
CFSTR("%s Primary service: %@ (%@)"),
elapsed(),
newPrimary,
newInterface != NULL ? newInterface : CFSTR("?"));
} else {
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
CFSTR("%s Primary service: removed"),
elapsed());
}
}
if (oldPrimary != NULL) CFRelease(oldPrimary);
oldPrimary = newPrimary;
if (entity != NULL) CFRelease(entity);
return;
}
static void
add_PrimaryService_notification()
{
CFStringRef key;
CFMutableArrayRef keys;
Boolean ok;
SCDynamicStoreRef store;
CFRunLoopSourceRef rls;
store = SCDynamicStoreCreate(NULL, CFSTR("Logger.bundle-PrimaryService"), PrimaryService_notification, NULL);
if (store == NULL) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreate() failed"));
return;
}
keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
CFArrayAppendValue(keys, key);
CFRelease(key);
ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL);
CFRelease(keys);
if (!ok) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreSetNotificationKeys() failed"));
CFRelease(store);
return;
}
rls = SCDynamicStoreCreateRunLoopSource(NULL, store, -1);
if (rls == NULL) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
CFRelease(store);
return;
}
CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
CFRelease(rls);
CFRelease(store);
return;
}
#pragma mark -
#pragma mark Reachability Events
static void
reachability_notification(SCNetworkReachabilityRef ref, SCNetworkReachabilityFlags flags, void *info)
{
CFStringRef hostname = (CFStringRef)info;
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
CFSTR("%s reachability changed: %@: flags=0x%08x"),
elapsed(),
hostname,
flags);
return;
}
static void
add_reachability_notification(CFArrayRef hosts)
{
SCNetworkReachabilityContext context = { 0, NULL, CFRetain, CFRelease, CFCopyDescription };
CFIndex i;
CFIndex n;
SCNetworkReachabilityRef target;
struct watch {
in_addr_t addr;
CFStringRef name;
} watchAddresses[] = { { 0, CFSTR("0.0.0.0") },
{ IN_LINKLOCALNETNUM, CFSTR("169.254.0.0") },
{ (u_int32_t)0xe00000fb, CFSTR("224.0.0.251") },
};
for (i = 0; i < sizeof(watchAddresses)/sizeof(watchAddresses[0]); i++) {
struct sockaddr_in sin;
bzero(&sin, sizeof(sin));
sin.sin_len = sizeof(sin);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(watchAddresses[i].addr);
target = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&sin);
if (target == NULL) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCNetworkReachabilityCreateWithAddress() failed"));
return;
}
context.info = (void *)watchAddresses[i].name;
if (!SCNetworkReachabilitySetCallback(target, reachability_notification, &context)) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCNetworkReachabilitySetCallback() failed"));
CFRelease(target);
return;
}
if (!SCNetworkReachabilityScheduleWithRunLoop(target, CFRunLoopGetCurrent(), kCFRunLoopCommonModes)) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCNetworkReachabilityScheduleWithRunLoop() failed"));
CFRelease(target);
return;
}
CFRelease(target);
}
n = (hosts != NULL) ? CFArrayGetCount(hosts) : 0;
for (i = 0; i < n; i++) {
CFStringRef host;
char *nodename;
host = CFArrayGetValueAtIndex(hosts, i);
if (!isA_CFString(host) || (CFStringGetLength(host) == 0)) {
continue;
}
nodename = _SC_cfstring_to_cstring(host, NULL, 0, kCFStringEncodingUTF8);
target = SCNetworkReachabilityCreateWithName(NULL, nodename);
CFAllocatorDeallocate(NULL, nodename);
if (target == NULL) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCNetworkReachabilityCreateWithName() failed"));
return;
}
context.info = (void *)host;
if (!SCNetworkReachabilitySetCallback(target, reachability_notification, &context)) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCNetworkReachabilitySetCallback() failed"));
CFRelease(target);
return;
}
if (!SCNetworkReachabilityScheduleWithRunLoop(target, CFRunLoopGetCurrent(), kCFRunLoopCommonModes)) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCNetworkReachabilityScheduleWithRunLoop() failed"));
CFRelease(target);
return;
}
CFRelease(target);
}
return;
}
#pragma mark -
#pragma mark Console User/Information Events
#if !TARGET_OS_EMBEDDED
static void
console_notification(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
{
gid_t gid;
CFArrayRef info;
CFMutableStringRef str = CFStringCreateMutable(NULL, 0);
uid_t uid;
CFStringRef user;
CFStringAppendFormat(str,
NULL,
CFSTR("%s SCDynamicStore console notification"),
elapsed());
user = SCDynamicStoreCopyConsoleUser(store, &uid, &gid);
if (user != NULL) {
CFStringAppendFormat(str, NULL, CFSTR("\nconsole user = %@"), user);
CFRelease(user);
} else {
CFStringAppendFormat(str, NULL, CFSTR("\nno console user"));
}
info = SCDynamicStoreCopyConsoleInformation(store);
if (info != NULL) {
CFIndex i;
CFIndex n;
n = CFArrayGetCount(info);
for (i = 0; i < n; i++) {
CFDictionaryRef session;
CFNumberRef sessionID;
CFStringRef sessionUserName;
CFBooleanRef sessionOnConsole;
session = CFArrayGetValueAtIndex(info, i);
sessionID = CFDictionaryGetValue(session, kSCConsoleSessionID);
sessionUserName = CFDictionaryGetValue(session, kSCConsoleSessionUserName);
sessionOnConsole = CFDictionaryGetValue(session, kSCConsoleSessionOnConsole);
CFStringAppendFormat(str, NULL, CFSTR("\n%d : id=%@, user=%@, console=%s"),
i,
sessionID,
sessionUserName != NULL ? sessionUserName : CFSTR("?"),
sessionOnConsole != NULL ? CFBooleanGetValue(sessionOnConsole) ? "yes" : "no" : "?");
}
CFRelease(info);
}
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO, CFSTR("%@"), str);
CFRelease(str);
return;
}
static void
add_console_notification()
{
CFStringRef key;
CFMutableArrayRef keys;
Boolean ok;
SCDynamicStoreRef store;
CFRunLoopSourceRef rls;
store = SCDynamicStoreCreate(NULL, CFSTR("Logger.bundle-console"), console_notification, NULL);
if (store == NULL) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreate() failed"));
return;
}
keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
key = SCDynamicStoreKeyCreateConsoleUser(NULL);
CFArrayAppendValue(keys, key);
CFRelease(key);
ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL);
CFRelease(keys);
if (!ok) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreSetNotificationKeys() failed"));
CFRelease(store);
return;
}
rls = SCDynamicStoreCreateRunLoopSource(NULL, store, -1);
if (rls == NULL) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
CFRelease(store);
return;
}
CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
CFRelease(rls);
CFRelease(store);
return;
}
#endif // !TARGET_OS_EMBEDDED
#pragma mark -
#pragma mark Directory Services Events
#ifndef kDSStdNotifySearchPolicyChanged
#define kDSStdNotifySearchPolicyChanged "com.apple.DirectoryService.NotifyTypeStandard:SearchPolicyChanged"
#endif
#if !TARGET_OS_EMBEDDED
static void
directoryServices_notification(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
{
CFIndex i;
CFIndex n;
CFMutableStringRef str = CFStringCreateMutable(NULL, 0);
CFStringAppendFormat(str,
NULL,
CFSTR("%s SCDynamicStore DirectoryServices notification"),
elapsed());
n = CFArrayGetCount(changedKeys);
for (i = 0; i < n; i++) {
CFStringRef key;
key = CFArrayGetValueAtIndex(changedKeys, i);
CFStringAppendFormat(str, NULL, CFSTR("\n%@"), key);
}
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO, CFSTR("%@"), str);
CFRelease(str);
return;
}
static void
add_DirectoryServices_notification()
{
CFStringRef key;
CFMutableArrayRef keys;
Boolean ok;
SCDynamicStoreRef store;
CFRunLoopSourceRef rls;
store = SCDynamicStoreCreate(NULL, CFSTR("Logger.bundle-directoryServices"), directoryServices_notification, NULL);
if (store == NULL) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreate() failed"));
return;
}
keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
key = CFSTR(kDSStdNotifySearchPolicyChanged);
CFArrayAppendValue(keys, key);
ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL);
CFRelease(keys);
if (!ok) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreSetNotificationKeys() failed"));
CFRelease(store);
return;
}
rls = SCDynamicStoreCreateRunLoopSource(NULL, store, -1);
if (rls == NULL) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
CFRelease(store);
return;
}
CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
CFRelease(rls);
CFRelease(store);
return;
}
#endif // !TARGET_OS_EMBEDDED
#pragma mark -
#pragma mark DNS Configuration Events
static void
dnsinfo_notification(CFMachPortRef port, void *msg, CFIndex size, void *info)
{
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
CFSTR("%s dnsinfo notification"),
elapsed());
return;
}
static void
add_dnsinfo_notification()
{
const char *key;
CFMachPortRef mp;
mach_port_t notify_port;
int notify_token;
CFRunLoopSourceRef rls;
uint32_t status;
key = dns_configuration_notify_key();
status = notify_register_mach_port(key, ¬ify_port, 0, ¬ify_token);
if (status != NOTIFY_STATUS_OK) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("notify_register_mach_port() failed"));
return;
}
mp = CFMachPortCreateWithPort(NULL, notify_port, dnsinfo_notification, NULL, NULL);
if (mp == NULL) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("CFMachPortCreateWithPort() failed"));
(void)notify_cancel(notify_token);
return;
}
rls = CFMachPortCreateRunLoopSource(NULL, mp, -1);
if (rls == NULL) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
CFRelease(mp);
(void)notify_cancel(notify_token);
return;
}
CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
CFRelease(rls);
CFRelease(mp);
return;
}
#pragma mark -
#pragma mark Network Configuration Change Events
#define NETWORKCHANGED_NOTIFY_KEY "com.apple.system.config.network_change"
static void
network_notification(CFMachPortRef port, void *msg, CFIndex size, void *info)
{
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
CFSTR("%s network_change notification"),
elapsed());
return;
}
static void
add_network_notification()
{
CFMachPortRef mp;
mach_port_t notify_port;
int notify_token;
CFRunLoopSourceRef rls;
uint32_t status;
status = notify_register_mach_port(NETWORKCHANGED_NOTIFY_KEY,
¬ify_port,
0,
¬ify_token);
if (status != NOTIFY_STATUS_OK) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("notify_register_mach_port() failed"));
return;
}
mp = CFMachPortCreateWithPort(NULL, notify_port, network_notification, NULL, NULL);
if (mp == NULL) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("CFMachPortCreateWithPort() failed"));
(void)notify_cancel(notify_token);
return;
}
rls = CFMachPortCreateRunLoopSource(NULL, mp, -1);
if (rls == NULL) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
CFRelease(mp);
(void)notify_cancel(notify_token);
return;
}
CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
CFRelease(rls);
CFRelease(mp);
return;
}
#pragma mark -
#pragma mark SMB Configuration Events
#define SMBCONFIGURATION_NOTIFY_KEY "com.apple.system.SystemConfiguration.smb_configuration"
#if !TARGET_OS_EMBEDDED
static void
smbconf_notification(CFMachPortRef port, void *msg, CFIndex size, void *info)
{
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO,
CFSTR("%s smb.conf notification"),
elapsed());
return;
}
static void
add_smbconf_notification()
{
CFMachPortRef mp;
mach_port_t notify_port;
int notify_token;
CFRunLoopSourceRef rls;
uint32_t status;
status = notify_register_mach_port(SMBCONFIGURATION_NOTIFY_KEY,
¬ify_port,
0,
¬ify_token);
if (status != NOTIFY_STATUS_OK) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("notify_register_mach_port() failed"));
return;
}
mp = CFMachPortCreateWithPort(NULL, notify_port, smbconf_notification, NULL, NULL);
if (mp == NULL) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("CFMachPortCreateWithPort() failed"));
(void)notify_cancel(notify_token);
return;
}
rls = CFMachPortCreateRunLoopSource(NULL, mp, -1);
if (rls == NULL) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
CFRelease(mp);
(void)notify_cancel(notify_token);
return;
}
CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
CFRelease(rls);
CFRelease(mp);
return;
}
#endif // !TARGET_OS_EMBEDDED
#pragma mark -
#pragma mark pututxline Events
#if !TARGET_OS_EMBEDDED
static const char *
ut_time(struct utmpx *utmpx)
{
static char str[16];
struct tm tm;
(void)localtime_r(&utmpx->ut_tv.tv_sec, &tm);
snprintf(str, sizeof(str), "%2d:%02d:%02d.%03d",
tm.tm_hour,
tm.tm_min,
tm.tm_sec,
utmpx->ut_tv.tv_usec / 1000);
return str;
}
static const char *
ut_id(struct utmpx *utmpx)
{
char *cp;
static char str[16];
cp = utmpx->ut_id + sizeof(utmpx->ut_id);
while(--cp >= utmpx->ut_id && isprint(*cp)) {}
if(cp < utmpx->ut_id) {
snprintf(str, sizeof(str), "%-4.4s", utmpx->ut_id);
} else {
snprintf(str, sizeof(str),
"0x%2.2x%2.2x%2.2x%2.2x",
utmpx->ut_id[0],
utmpx->ut_id[1],
utmpx->ut_id[2],
utmpx->ut_id[3]);
}
return str;
}
static const char *
ut_pid(struct utmpx *utmpx)
{
static char pid[16];
snprintf(pid, sizeof(pid), "%d", utmpx->ut_pid);
return pid;
}
static void
pututxline_notification(CFMachPortRef port, void *msg, CFIndex size, void *info)
{
CFMutableStringRef str = CFStringCreateMutable(NULL, 0);
struct utmpx *utmpx;
CFStringAppendFormat(str,
NULL,
CFSTR("%s pututxline notification"),
elapsed());
setutxent();
while ((utmpx = getutxent()) != NULL) {
const char * entry_id = NULL;
const char * entry_line = NULL;
const char * entry_pid = NULL;
const char * entry_tv = NULL;
const char * entry_type;
const char * entry_user = NULL;
char line[128];
int n;
switch (utmpx->ut_type) {
case BOOT_TIME : entry_type = "Boot";
entry_tv = ut_time(utmpx);
break;
case DEAD_PROCESS : entry_type = "Dead process";
entry_id = ut_id (utmpx);
entry_pid = ut_pid (utmpx);
entry_tv = ut_time(utmpx);
break;
case EMPTY : continue;
case INIT_PROCESS : entry_type = "Init process";
entry_id = ut_id (utmpx);
entry_pid = ut_pid (utmpx);
entry_tv = ut_time(utmpx);
break;
case LOGIN_PROCESS : entry_type = "Login";
entry_id = ut_id (utmpx);
entry_user = utmpx->ut_user;
entry_pid = ut_pid (utmpx);
entry_tv = ut_time(utmpx);
break;
case NEW_TIME : entry_type = "New time";
entry_tv = ut_time(utmpx);
break;
case OLD_TIME : entry_type = "Old time";
entry_tv = ut_time(utmpx);
break;
case RUN_LVL : entry_type = "Run level";
break;
case USER_PROCESS : entry_type = "User Process";
entry_id = ut_id (utmpx);
entry_user = utmpx->ut_user;
entry_line = utmpx->ut_line;
entry_pid = ut_pid (utmpx);
entry_tv = ut_time(utmpx);
break;
case SHUTDOWN_TIME : entry_type = "Shutdown time";
entry_tv = ut_time(utmpx);
break;
default :
entry_type = "Unknown";
break;
}
snprintf(line, sizeof(line),
"\n%-13s %2s%12s %3s%-10s %4s%-5s %5s%-8s %5s%s",
entry_type,
entry_tv != NULL ? "@ " : "",
entry_tv != NULL ? entry_tv : "", entry_id != NULL ? "id=" : "",
entry_id != NULL ? entry_id : "", entry_pid != NULL ? "pid=" : "",
entry_pid != NULL ? entry_pid : "", entry_user != NULL ? "user=" : "",
entry_user != NULL ? entry_user : "", entry_line != NULL ? "line=" : "",
entry_line != NULL ? entry_line : "" );
n = strlen(line) - 1;
while ((n > 0) && (line[n] == ' ')) {
line[n] = '\0';
--n;
}
CFStringAppendFormat(str, NULL, CFSTR("%s"), line);
}
endutxent();
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO, CFSTR("%@"), str);
CFRelease(str);
return;
}
static void
add_pututxline_notification()
{
CFMachPortRef mp;
mach_port_t notify_port;
int notify_token;
CFRunLoopSourceRef rls;
uint32_t status;
status = notify_register_mach_port(UTMPX_CHANGE_NOTIFICATION, ¬ify_port, 0, ¬ify_token);
if (status != NOTIFY_STATUS_OK) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("notify_register_mach_port() failed"));
return;
}
mp = CFMachPortCreateWithPort(NULL, notify_port, pututxline_notification, NULL, NULL);
if (mp == NULL) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("CFMachPortCreateWithPort() failed"));
(void)notify_cancel(notify_token);
return;
}
rls = CFMachPortCreateRunLoopSource(NULL, mp, -1);
if (rls == NULL) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
CFRelease(mp);
(void)notify_cancel(notify_token);
return;
}
CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
CFRelease(rls);
CFRelease(mp);
return;
}
#endif // !TARGET_OS_EMBEDDED
#pragma mark -
#pragma mark BackToMyMac Status Events
#ifndef kDSStdNotifyBTMMStatusChanged
#define kDSStdNotifyBTMMStatusChanged "State:/Network/BackToMyMac"
#endif
#if !TARGET_OS_EMBEDDED
static void
BTMM_notification(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context)
{
CFIndex i;
CFIndex n;
CFMutableStringRef str = CFStringCreateMutable(NULL, 0);
CFStringAppendFormat(str,
NULL,
CFSTR("%s SCDynamicStore Back to My Mac notification"),
elapsed());
n = CFArrayGetCount(changedKeys);
for (i = 0; i < n; i++) {
CFStringRef key;
CFDictionaryRef dict;
key = CFArrayGetValueAtIndex(changedKeys, i);
dict = SCDynamicStoreCopyValue(store, key);
if (dict != NULL) {
CFStringRef val;
val = _SCCopyDescription(dict, NULL);
CFStringAppendFormat(str, NULL, CFSTR("\n%@ : %@"), key, val);
CFRelease(val);
CFRelease(dict);
} else {
CFStringAppendFormat(str, NULL, CFSTR("\n%@ : removed"), key);
}
}
SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO, CFSTR("%@"), str);
CFRelease(str);
return;
}
static void
add_BTMM_notification()
{
CFStringRef key;
CFMutableArrayRef keys;
Boolean ok;
SCDynamicStoreRef store;
CFRunLoopSourceRef rls;
store = SCDynamicStoreCreate(NULL, CFSTR("Logger.bundle-BackToMyMac"), BTMM_notification, NULL);
if (store == NULL) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreate() failed"));
return;
}
keys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
key = CFSTR(kDSStdNotifyBTMMStatusChanged);
CFArrayAppendValue(keys, key);
ok = SCDynamicStoreSetNotificationKeys(store, keys, NULL);
CFRelease(keys);
if (!ok) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreSetNotificationKeys() failed"));
CFRelease(store);
return;
}
rls = SCDynamicStoreCreateRunLoopSource(NULL, store, -1);
if (rls == NULL) {
SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
CFRelease(store);
return;
}
CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
CFRelease(rls);
CFRelease(store);
return;
}
#endif // !TARGET_OS_EMBEDDED
#pragma mark -
static inline Boolean
bValFromDictionary(CFDictionaryRef dict, CFStringRef key)
{
CFBooleanRef bVal;
Boolean result = FALSE;
if ((dict != NULL) &&
CFDictionaryGetValueIfPresent(dict, key, (const void **)&bVal) &&
isA_CFBoolean(bVal)) {
result = CFBooleanGetValue(bVal);
}
return result;
}
void
load(CFBundleRef bundle, Boolean bundleVerbose)
{
CFDictionaryRef config;
Boolean log_all;
verbose = bundleVerbose;
log_msg = asl_new(ASL_TYPE_MSG);
asl_set(log_msg, ASL_KEY_FACILITY, MY_ASL_FACILITY);
elapsed();
config = CFBundleGetInfoDictionary(bundle);
config = isA_CFDictionary(config);
log_all = bValFromDictionary(config, CFSTR("LOG_ALL"));
#ifdef kIOPMMessageSleepWakeUUIDChange
if (log_all || bValFromDictionary(config, CFSTR("LOG_IO_WAKEUUID_EVENTS"))) {
add_wake_uuid_notification();
}
#endif // kIOPMMessageSleepWakeUUIDChange
if (log_all || bValFromDictionary(config, CFSTR("LOG_IO_SYSTEMPOWER_EVENTS"))) {
add_power_notification();
}
if (log_all || bValFromDictionary(config, CFSTR("LOG_NETWORK_KERNEL_EVENTS"))) {
add_KernelEvent_notification();
}
if (log_all || bValFromDictionary(config, CFSTR("LOG_NOTIFY_DNS_CONFIGURATION"))) {
add_dnsinfo_notification();
}
if (log_all || bValFromDictionary(config, CFSTR("LOG_NOTIFY_NETWORK_CHANGE"))) {
add_network_notification();
}
#if !TARGET_OS_EMBEDDED
if (log_all || bValFromDictionary(config, CFSTR("LOG_NOTIFY_SMB_CONFIGURATION"))) {
add_smbconf_notification();
}
#endif // !TARGET_OS_EMBEDDED
#if !TARGET_OS_EMBEDDED
if (log_all || bValFromDictionary(config, CFSTR("LOG_NOTIFY_UTMPX_CHANGE"))) {
add_pututxline_notification();
}
#endif // !TARGET_OS_EMBEDDED
#if !TARGET_OS_EMBEDDED
if (log_all || bValFromDictionary(config, CFSTR("LOG_SC_BTMM_CONFIGURATION"))) {
add_BTMM_notification();
}
#endif // !TARGET_OS_EMBEDDED
#if !TARGET_OS_EMBEDDED
if (log_all || bValFromDictionary(config, CFSTR("LOG_SC_CONSOLEUSER"))) {
add_console_notification();
}
#endif // !TARGET_OS_EMBEDDED
#if !TARGET_OS_EMBEDDED
if (log_all || bValFromDictionary(config, CFSTR("LOG_SC_DIRECTORYSERVICES_SEARCHPOLICY"))) {
add_DirectoryServices_notification();
}
#endif // !TARGET_OS_EMBEDDED
if (log_all || bValFromDictionary(config, CFSTR("LOG_SC_NETWORKCHANGE"))) {
add_NetworkChange_notification();
}
if (log_all || bValFromDictionary(config, CFSTR("LOG_SC_PRIMARYSERVICE"))) {
add_PrimaryService_notification();
}
if (log_all || bValFromDictionary(config, CFSTR("LOG_SC_REACHABILITY"))) {
CFArrayRef hosts = NULL;
if ((config == NULL) ||
!CFDictionaryGetValueIfPresent(config, CFSTR("LOG_SC_REACHABILITY_HOSTS"), (const void **)&hosts) ||
!isA_CFArray(hosts) ||
(CFArrayGetCount(hosts) == 0)) {
hosts = NULL;
}
add_reachability_notification(hosts);
}
return;
}
#ifdef MAIN
int
main(int argc, char **argv)
{
_sc_log = FALSE;
_sc_verbose = (argc > 1) ? TRUE : FALSE;
_sc_debug = TRUE;
load(CFBundleGetMainBundle(), (argc > 1) ? TRUE : FALSE);
CFRunLoopRun();
exit(0);
return 0;
}
#endif