extern "C" {
#include <sys/time.h>
#include <pexpert/pexpert.h>
}
#include <sys/unistd.h>
#include <sys/systm.h>
#include <IOKit/IOLib.h>
#include <IOKit/IOLocks.h>
#include "KLog.h"
#include "KLogClient.h"
#define super IOService
#define TIMESTAMPSIZE sizeof(struct klog64_timeval)
#define LEVELSIZE sizeof(uint32_t)
#define TAGSIZE sizeof(uint32_t)
#define DATAOFFSET (TIMESTAMPSIZE + LEVELSIZE + TAGSIZE)
#define MSGSIZE BUFSIZE - (TIMESTAMPSIZE + LEVELSIZE + TAGSIZE)
#define DEBUG_NAME "[KLog]"
com_apple_iokit_KLog * com_apple_iokit_KLog::sLogger = NULL;
OSDefineMetaClassAndStructors( com_apple_iokit_KLog, IOService )
#pragma mark -
#pragma mark ¥ IOService Overrides ¥
bool com_apple_iokit_KLog::init(OSDictionary *dict)
{
bool res = super::init(dict);
mClientCount=0;
mMsgSize = MSGSIZE;
mMsgBuffer = (unsigned char *)IOMalloc(mMsgSize + DATAOFFSET + 1);
for(UInt8 i=0; i<MAXUSERS;i++)
mClientPtr[i]=NULL;
mErrFlag = false;
mTimeVal = new klog64_timeval;
mLogLock = IOLockAlloc();
sLogger = this;
return res;
}
void com_apple_iokit_KLog::free(void)
{
sLogger = NULL;
if (mLogLock) {
IOLockFree(mLogLock);
mLogLock = NULL;
}
if (mMsgBuffer) {
IOFree(mMsgBuffer, mMsgSize + DATAOFFSET + 1);
mMsgBuffer = NULL;
}
super::free();
}
IOService * com_apple_iokit_KLog::probe(IOService *provider, SInt32 *score)
{
IOService *res = super::probe(provider, score);
return res;
}
bool com_apple_iokit_KLog::start(IOService *provider)
{
bool res = super::start(provider);
registerService();
return res;
}
void com_apple_iokit_KLog::stop(IOService *provider)
{
super::stop(provider);
}
void com_apple_iokit_KLog::closeChild(com_apple_iokit_KLogClient *ptr)
{
UInt8 i, idx;
idx = 0;
if(mClientCount == 0)
{
IOLog( DEBUG_NAME "No clients available to close");
return;
}
IOLog( DEBUG_NAME "Closing: %p\n",ptr);
for(i=0;i<mClientCount;i++)
{
IOLog( DEBUG_NAME "userclient ref: %d %p\n", i, mClientPtr[i]);
}
for(i=0;i<mClientCount;i++)
{
if(mClientPtr[i] == ptr)
{
mClientCount--;
mClientPtr[i] = NULL;
idx = i;
i = mClientCount+1;
}
}
for(i=idx;i<mClientCount;i++)
{
mClientPtr[i] = mClientPtr[i+1];
}
mClientPtr[mClientCount+1] = NULL;
}
IOReturn com_apple_iokit_KLog::newUserClient( task_t owningTask, void * securityID,
UInt32 type, IOUserClient ** handler )
{
IOReturn ioReturn = kIOReturnSuccess;
com_apple_iokit_KLogClient *client = NULL;
if(mClientCount > MAXUSERS)
{
IOLog( DEBUG_NAME "client already created, not deleted\n");
return(kIOReturnError);
}
client = com_apple_iokit_KLogClient::withTask(owningTask);
if (client == NULL) {
ioReturn = kIOReturnNoResources;
IOLog("KLog::newUserClient: Can't create user client\n");
}
if (ioReturn == kIOReturnSuccess) {
client->attach(this);
if (client->start(this) == false) {
ioReturn = kIOReturnError;
IOLog("KLog::newUserClient: Can't start user client\n");
}
}
if (ioReturn != kIOReturnSuccess && client != NULL) {
IOLog( DEBUG_NAME "newUserClient error\n");
client->detach(this);
client->release();
} else {
mClientPtr[mClientCount] = client;
*handler = client;
client->set_Q_Size(type);
mClientCount++;
}
IOLog( DEBUG_NAME "neUserClient() client = %p\n", mClientPtr[mClientCount]);
return (ioReturn);
}
#pragma mark -
#pragma mark ¥ Class specific stuff ¥
void com_apple_iokit_KLog::setErr( bool set )
{
mErrFlag = set;
}
#pragma mark -
#pragma mark ¥ Logging ¥
SInt8 com_apple_iokit_KLog::Log( KLogLevel level, KLogTag tag, const char *format, ... )
{
SInt8 result;
va_list argList;
va_start(argList, format);
result = vLog( tag, level, format, argList );
va_end( argList );
return( result );
}
SInt8 com_apple_iokit_KLog::vLog( KLogLevel level, KLogTag tag, const char *format, va_list inArgList )
{
UInt8 i;
UInt32 returnValue = 0;
struct timeval timeVal;
if(!format)
{
return 0;
}
IOLockLock(mLogLock);
if(mClientCount == 0)
{
returnValue = 0;
goto exit;
}
microtime(&timeVal);
mTimeVal->tv_sec = timeVal.tv_sec;
mTimeVal->tv_usec = timeVal.tv_usec;
memcpy(mMsgBuffer, mTimeVal, TIMESTAMPSIZE);
memcpy((mMsgBuffer + TIMESTAMPSIZE), &tag, TAGSIZE);
memcpy((mMsgBuffer + TIMESTAMPSIZE + TAGSIZE), &level, LEVELSIZE);
returnValue = vsnprintf(((char*)mMsgBuffer + DATAOFFSET), (mMsgSize + 1), format, inArgList);
if ((int)returnValue > mMsgSize)
{
IOFree(mMsgBuffer, (mMsgSize + DATAOFFSET + 1));
mMsgSize = returnValue;
mMsgBuffer = (unsigned char *)IOMalloc(mMsgSize + DATAOFFSET + 1);
memcpy(mMsgBuffer, mTimeVal, TIMESTAMPSIZE);
memcpy((mMsgBuffer + TIMESTAMPSIZE), &tag, TAGSIZE);
memcpy((mMsgBuffer + TIMESTAMPSIZE + TAGSIZE), &level, LEVELSIZE);
returnValue = vsnprintf(((char*)mMsgBuffer + DATAOFFSET), (mMsgSize + 1), format, inArgList);
IOLog( DEBUG_NAME "Resized my mMsgBuffer to %d\n", (int)returnValue);
}
if(!mErrFlag)
{
for(i=0 ; i<=mClientCount ; i++)
{
if(mClientPtr[i] != NULL)
{
mClientPtr[i]->AddEntry((void*)mMsgBuffer, (returnValue + DATAOFFSET + 1));
}
}
}
exit:
IOLockUnlock(mLogLock);
return returnValue;
}