#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <stdarg.h>
#include <regex.h>
#include <syslog.h>
#include <errno.h>
#include <time.h>
#include <sys/time.h>
#include <asl.h>
#include <asl_private.h>
#include <asl_core.h>
#include <sys/types.h>
#include <libkern/OSAtomic.h>
#include <assert.h>
#include "asl_msg.h"
#define TOKEN_NULL 0
#define TOKEN_OPEN 1
#define TOKEN_CLOSE 2
#define TOKEN_WORD 3
#define TOKEN_INT 4
#define MFMT_RAW 0
#define MFMT_STD 1
#define MFMT_BSD 2
#define MFMT_XML 3
#define MFMT_STR 4
#define MFMT_MSG 5
#define SEC_PER_HOUR 3600
#define forever for(;;)
#define streq(A, B) (strcmp(A, B) == 0)
#define streq_len(A, B, C) (strncmp(A, B, C) == 0)
#define strneq(A, B) (strcmp(A, B) != 0)
#define strcaseeq(A, B) (strcasecmp(A, B) == 0)
#define strcaseneq(A, B) (strcasecmp(A, B) != 0)
#ifndef ASL_KEY_OPTION
#define ASL_KEY_OPTION "ASLOption"
#endif
#ifndef ASL_QUERY_OP_FALSE
#define ASL_QUERY_OP_FALSE 0
#endif
#define AUX_0_TIME 0x00000001
#define AUX_0_TIME_NSEC 0x00000002
#define AUX_0_HOST 0x00000004
#define AUX_0_SENDER 0x00000008
#define AUX_0_FACILITY 0x00000010
#define AUX_0_PID 0x00000020
#define AUX_0_UID 0x00000040
#define AUX_0_GID 0x00000080
#define AUX_0_MSG 0x00000100
#define AUX_0_OPTION 0x00000200
#define AUX_0_LEVEL 0x00000400
extern time_t asl_parse_time(const char *in);
int asl_is_utf8(const char *str);
uint8_t *asl_b64_encode(const uint8_t *buf, size_t len);
static const char *ASLStandardKey[] =
{
ASL_KEY_TIME,
ASL_KEY_TIME_NSEC,
ASL_KEY_HOST,
ASL_KEY_SENDER,
ASL_KEY_FACILITY,
ASL_KEY_PID,
ASL_KEY_UID,
ASL_KEY_GID,
ASL_KEY_LEVEL,
ASL_KEY_MSG,
ASL_KEY_READ_UID,
ASL_KEY_READ_GID,
ASL_KEY_SESSION,
ASL_KEY_REF_PID,
ASL_KEY_REF_PROC,
ASL_KEY_MSG_ID,
ASL_KEY_EXPIRE_TIME,
ASL_KEY_OPTION
};
static const char *MTStandardKey[] =
{
"com.apple.message.domain",
"com.apple.message.domain_scope",
"com.apple.message.result",
"com.apple.message.signature",
"com.apple.message.signature2",
"com.apple.message.signature3",
"com.apple.message.success",
"com.apple.message.uuid",
"com.apple.message.value",
"com.apple.message.value2",
"com.apple.message.value3",
"com.apple.message.value4",
"com.apple.message.value5"
};
static uint16_t
_asl_msg_std_key(const char *s, uint32_t len)
{
if ((len > 18) && (streq_len(s, "com.apple.message.", 18)))
{
if (streq(s + 18, "domain")) return ASL_MT_KEY_DOMAIN;
else if (streq(s + 18, "domain_scope")) return ASL_MT_KEY_SCOPE;
else if (streq(s + 18, "result")) return ASL_MT_KEY_RESULT;
else if (streq(s + 18, "signature")) return ASL_MT_KEY_SIG;
else if (streq(s + 18, "signature2")) return ASL_MT_KEY_SIG2;
else if (streq(s + 18, "signature3")) return ASL_MT_KEY_SIG3;
else if (streq(s + 18, "success")) return ASL_MT_KEY_SUCCESS;
else if (streq(s + 18, "uuid")) return ASL_MT_KEY_UUID;
else if (streq(s + 18, "value")) return ASL_MT_KEY_VAL;
else if (streq(s + 18, "value2")) return ASL_MT_KEY_VAL2;
else if (streq(s + 18, "value3")) return ASL_MT_KEY_VAL3;
else if (streq(s + 18, "value4")) return ASL_MT_KEY_VAL4;
else if (streq(s + 18, "value5")) return ASL_MT_KEY_VAL5;
return 0;
}
switch (len)
{
case 3:
{
if streq(s, ASL_KEY_PID) return ASL_STD_KEY_PID;
else if streq(s, ASL_KEY_UID) return ASL_STD_KEY_UID;
else if streq(s, ASL_KEY_GID) return ASL_STD_KEY_GID;
}
case 4:
{
if streq(s, ASL_KEY_TIME) return ASL_STD_KEY_TIME;
else if streq(s, ASL_KEY_HOST) return ASL_STD_KEY_HOST;
}
case 5:
{
if streq(s, ASL_KEY_LEVEL) return ASL_STD_KEY_LEVEL;
}
case 6:
{
if streq(s, ASL_KEY_SENDER) return ASL_STD_KEY_SENDER;
else if streq(s, ASL_KEY_REF_PID) return ASL_STD_KEY_REF_PID;
}
case 7:
{
if streq(s, ASL_KEY_MSG) return ASL_STD_KEY_MESSAGE;
else if streq(s, ASL_KEY_SESSION) return ASL_STD_KEY_SESSION;
else if streq(s, ASL_KEY_READ_UID) return ASL_STD_KEY_READ_UID;
else if streq(s, ASL_KEY_READ_GID) return ASL_STD_KEY_READ_GID;
else if streq(s, ASL_KEY_REF_PROC) return ASL_STD_KEY_REF_PROC;
}
case 8:
{
if streq(s, ASL_KEY_FACILITY) return ASL_STD_KEY_FACILITY;
}
case 9:
{
if streq(s, ASL_KEY_OPTION) return ASL_STD_KEY_OPTION;
}
case 11:
{
if streq(s, ASL_KEY_TIME_NSEC) return ASL_STD_KEY_NANO;
}
case 12:
{
if streq(s, ASL_KEY_MSG_ID) return ASL_STD_KEY_MSG_ID;
}
case 13:
{
if streq(s, ASL_KEY_EXPIRE_TIME) return ASL_STD_KEY_EXPIRE;
}
default:
{
return 0;
}
}
return 0;
}
static asl_msg_t *
_asl_msg_make_page()
{
asl_msg_t *out;
int i;
out = calloc(1, sizeof(asl_msg_t));
if (out == NULL) return NULL;
for (i = 0; i < ASL_MSG_PAGE_SLOTS; i++)
{
out->key[i] = ASL_MSG_SLOT_FREE;
out->val[i] = ASL_MSG_SLOT_FREE;
}
return out;
}
static const char *
_asl_msg_slot_key(asl_msg_t *page, uint32_t slot)
{
const char *out;
uint16_t x;
if (page == NULL) return NULL;
if (slot >= ASL_MSG_PAGE_SLOTS) return NULL;
if (page->key[slot] == ASL_MSG_SLOT_FREE) return NULL;
switch (page->key[slot] & ASL_MSG_KV_MASK)
{
case ASL_MSG_KV_INLINE:
{
return page->data + page->key[slot];
}
case ASL_MSG_KV_DICT:
{
if ((page->key[slot] > ASL_STD_KEY_BASE) && (page->key[slot] <= ASL_STD_KEY_LAST))
{
x = page->key[slot] - ASL_STD_KEY_BASE - 1;
return ASLStandardKey[x];
}
else if ((page->key[slot] > ASL_MT_KEY_BASE) && (page->key[slot] <= ASL_MT_KEY_LAST))
{
x = page->key[slot] - ASL_MT_KEY_BASE - 1;
return MTStandardKey[x];
}
return NULL;
}
case ASL_MSG_KV_EXTERN:
{
x = page->key[slot] & ASL_MSG_OFFSET_MASK;
memcpy(&out, page->data + x, sizeof(char *));
return out;
}
}
return NULL;
}
static const char *
_asl_msg_slot_val(asl_msg_t *page, uint32_t slot)
{
const char *out;
uint16_t x, type;
if (page == NULL) return NULL;
if (slot >= ASL_MSG_PAGE_SLOTS) return NULL;
if (page->val[slot] == ASL_MSG_SLOT_FREE) return NULL;
type = page->val[slot] & ASL_MSG_KV_MASK;
if (type == ASL_MSG_KV_INLINE)
{
return page->data + page->val[slot];
}
else if (type == ASL_MSG_KV_EXTERN)
{
x = page->val[slot] & ASL_MSG_OFFSET_MASK;
memcpy(&out, page->data + x, sizeof(char *));
return out;
}
return NULL;
}
asl_msg_t *
asl_msg_new(uint32_t type)
{
asl_msg_t *out;
out = _asl_msg_make_page();
if (out == NULL) return NULL;
out->type = type;
out->refcount = 1;
return out;
}
asl_msg_t *
asl_msg_retain(asl_msg_t *msg)
{
int32_t new;
if (msg == NULL) return NULL;
new = OSAtomicIncrement32Barrier(&msg->refcount);
assert(new >= 1);
return msg;
}
static void
_asl_msg_free(asl_msg_t *page)
{
uint32_t i;
char *p;
if (page == NULL) return;
for (i = 0; i < ASL_MSG_PAGE_SLOTS; i++)
{
if ((page->key[i] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
{
memcpy(&p, page->data + (page->key[i] & ASL_MSG_OFFSET_MASK), sizeof(char *));
free(p);
}
if ((page->val[i] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
{
memcpy(&p, page->data + (page->val[i] & ASL_MSG_OFFSET_MASK), sizeof(char *));
free(p);
}
}
free(page);
}
void
asl_msg_release(asl_msg_t *msg)
{
int32_t new;
asl_msg_t *next;
if (msg == NULL) return;
new = OSAtomicDecrement32Barrier(&msg->refcount);
assert(new >= 0);
if (new > 0) return;
while (msg != NULL)
{
next = msg->next;
_asl_msg_free(msg);
msg = next;
}
}
static uint32_t
_asl_msg_index(asl_msg_t *msg, const char *key, uint32_t *oslot, asl_msg_t **opage)
{
uint32_t i, len, slot;
uint16_t kx;
asl_msg_t *page;
const char *kp;
if (msg == NULL) return IndexNull;
if (key == NULL) return IndexNull;
i = 0;
slot = 0;
if (oslot != NULL) *oslot = slot;
page = msg;
if (opage != NULL) *opage = page;
len = strlen(key);
kx = _asl_msg_std_key(key, len);
forever
{
if (page->key[slot] != ASL_MSG_SLOT_FREE)
{
if (kx != 0)
{
if (page->key[slot] == kx) return i;
}
else if ((page->key[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_DICT)
{
}
else if ((page->key[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
{
memcpy(&kp, page->data + (page->key[slot] & ASL_MSG_OFFSET_MASK), sizeof(char *));
if (streq(key, kp)) return i;
}
else
{
kp = page->data + page->key[slot];
if (streq(key, kp)) return i;
}
}
i++;
slot++;
if (oslot != NULL) *oslot = slot;
if (slot >= ASL_MSG_PAGE_SLOTS)
{
if (page->next == NULL) return IndexNull;
slot = 0;
if (oslot != NULL) *oslot = slot;
page = page->next;
if (opage != NULL) *opage = page;
}
}
return IndexNull;
}
static uint32_t
_asl_msg_fetch_internal(asl_msg_t *msg, uint32_t n, const char **keyout, const char **valout, uint32_t *opout, asl_msg_t **outpage, uint32_t *outslot)
{
uint32_t slot;
asl_msg_t *page;
if (msg == NULL) return IndexNull;
if (outpage != NULL) *outpage = NULL;
if (outslot != NULL) *outslot = IndexNull;
slot = n;
page = msg;
while (slot >= ASL_MSG_PAGE_SLOTS)
{
if (page->next == NULL) return IndexNull;
page = page->next;
slot -= ASL_MSG_PAGE_SLOTS;
}
while (page->key[slot] == ASL_MSG_SLOT_FREE)
{
slot++;
n++;
if (slot >= ASL_MSG_PAGE_SLOTS)
{
if (page->next == NULL) return IndexNull;
page = page->next;
slot = 0;
}
}
n++;
if (keyout != NULL) *keyout = _asl_msg_slot_key(page, slot);
if (valout != NULL) *valout = _asl_msg_slot_val(page, slot);
if (opout != NULL) *opout = page->op[slot];
if (outpage != NULL) *outpage = page;
if (outslot != NULL) *outslot = slot;
return n;
}
uint32_t
asl_msg_fetch(asl_msg_t *msg, uint32_t n, const char **keyout, const char **valout, uint32_t *opout)
{
return _asl_msg_fetch_internal(msg, n, keyout, valout, opout, NULL, NULL);
}
static int
_asl_msg_new_key_val_op(asl_msg_t *msg, const char *key, const char *val, uint32_t op)
{
uint32_t slot, keylen, vallen, total;
uint16_t kx;
asl_msg_t *page, *last;
char *extkey, *extval;
if (msg == NULL) return -1;
if (key == NULL) return -1;
extkey = NULL;
extval = NULL;
keylen = strlen(key);
kx = _asl_msg_std_key(key, keylen);
if (kx == 0) keylen++;
else keylen = 0;
total = keylen;
vallen = 0;
if (val != NULL)
{
vallen = strlen(val) + 1;
total += vallen;
}
if (keylen > ASL_MSG_PAGE_DATA_SIZE)
{
extkey = strdup(key);
keylen = sizeof(char *);
}
if (vallen > ASL_MSG_PAGE_DATA_SIZE)
{
extval = strdup(val);
vallen = sizeof(char *);
}
total = keylen + vallen;
if ((total > ASL_MSG_PAGE_DATA_SIZE) && (extval == NULL) && (keylen > 0))
{
extval = strdup(val);
vallen = sizeof(char *);
total = keylen + vallen;
}
if ((total > ASL_MSG_PAGE_DATA_SIZE) && (extkey == NULL))
{
extkey = strdup(key);
keylen = sizeof(char *);
total = keylen + vallen;
}
if (total > ASL_MSG_PAGE_DATA_SIZE)
{
if (extkey != NULL) free(extkey);
if (extval != NULL) free(extval);
return -1;
}
slot = 0;
last = msg;
for (page = msg; page != NULL; page = page->next)
{
last = page;
if (total <= (ASL_MSG_PAGE_DATA_SIZE - page->data_size))
{
for (slot = 0; (slot < ASL_MSG_PAGE_SLOTS) && (page->key[slot] != ASL_MSG_SLOT_FREE); slot++);
if (slot < ASL_MSG_PAGE_SLOTS) break;
}
}
if (page == NULL)
{
page = _asl_msg_make_page();
if (page == NULL)
{
if (extkey != NULL) free(extkey);
if (extval != NULL) free(extval);
return -1;
}
last->next = page;
slot = 0;
}
if (kx != 0)
{
page->key[slot] = kx;
}
else if (extkey == NULL)
{
page->key[slot] = page->data_size;
memcpy(page->data + page->data_size, key, keylen);
}
else
{
page->key[slot] = page->data_size | ASL_MSG_KV_EXTERN;
memcpy(page->data + page->data_size, &extkey, keylen);
}
page->data_size += keylen;
page->val[slot] = ASL_MSG_SLOT_FREE;
if (val != NULL)
{
if (extval == NULL)
{
page->val[slot] = page->data_size;
memcpy(page->data + page->data_size, val, vallen);
}
else
{
page->val[slot] = page->data_size | ASL_MSG_KV_EXTERN;
memcpy(page->data + page->data_size, &extval, vallen);
}
page->data_size += vallen;
}
page->op[slot] = op;
page->count++;
return 0;
}
static int
_asl_msg_set_kvo(asl_msg_t *msg, const char *key, const char *val, uint32_t op)
{
uint32_t i, slot, newexternal;
asl_msg_t *page;
uint32_t intvallen, extvallen, newvallen;
char *intval, *extval, *newval;
if (msg == NULL) return -1;
if (key == NULL) return -1;
slot = IndexNull;
page = NULL;
if ((msg->type == ASL_TYPE_QUERY) || (IndexNull == _asl_msg_index(msg, key, &slot, &page)))
{
return _asl_msg_new_key_val_op(msg, key, val, op);
}
intval = NULL;
intvallen = 0;
extval = NULL;
extvallen = 0;
if (page->val[slot] != ASL_MSG_SLOT_FREE)
{
if ((page->val[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
{
i = page->val[slot] & ASL_MSG_OFFSET_MASK;
memcpy(&extval, page->data + i, sizeof(char *));
extvallen = sizeof(char *);
}
else
{
intval = page->data + page->val[slot];
intvallen = strlen(intval) + 1;
}
}
if (val == NULL)
{
if (extval != NULL) free(extval);
page->val[slot] = ASL_MSG_SLOT_FREE;
if (op != IndexNull) page->op[slot] = op;
return 0;
}
if ((intval != NULL) && (streq(val, intval)))
{
if (op != IndexNull) page->op[slot] = op;
return 0;
}
if ((extval != NULL) && (streq(val, extval)))
{
if (op != IndexNull) page->op[slot] = op;
return 0;
}
i = page->val[slot] & ASL_MSG_OFFSET_MASK;
if ((intval != NULL) && ((i + intvallen) == page->data_size))
{
page->val[slot] = ASL_MSG_SLOT_FREE;
page->data_size -= intvallen;
intval = NULL;
intvallen = 0;
}
else if ((extval != NULL) && ((i + extvallen) == page->data_size))
{
page->val[slot] = ASL_MSG_SLOT_FREE;
page->data_size -= extvallen;
free(extval);
extval = NULL;
extvallen = 0;
}
newvallen = strlen(val) + 1;
newexternal = 0;
if (newvallen > ASL_MSG_PAGE_DATA_SIZE)
{
newexternal = 1;
newvallen = sizeof(char *);
}
if (((extval != NULL) && (newvallen <= extvallen)) || ((extval == NULL) && (newvallen <= intvallen)))
{
if (extval != NULL) free(extval);
extval = NULL;
i = page->val[slot] & ASL_MSG_OFFSET_MASK;
if (newexternal == 1)
{
newval = strdup(val);
if (newval == NULL) return -1;
page->val[slot] = i | ASL_MSG_KV_EXTERN;
memcpy(page->data + i, &newval, sizeof(char *));
}
else
{
page->val[slot] = i;
memcpy(page->data + i, val, newvallen);
}
if (op != IndexNull) page->op[slot] = op;
return 0;
}
if (extval != NULL) free(extval);
extval = NULL;
if (newvallen <= (ASL_MSG_PAGE_DATA_SIZE - page->data_size))
{
i = page->data_size;
page->data_size += newvallen;
if (newexternal == 1)
{
newval = strdup(val);
if (newval == NULL) return -1;
page->val[slot] = i | ASL_MSG_KV_EXTERN;
memcpy(page->data + i, &newval, sizeof(char *));
}
else
{
page->val[slot] = i;
memcpy(page->data + i, val, newvallen);
}
if (op != IndexNull) page->op[slot] = op;
return 0;
}
if ((page->key[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
{
memcpy(&extval, page->data + (page->key[slot] & ASL_MSG_OFFSET_MASK), sizeof(char *));
free(extval);
}
page->key[slot] = ASL_MSG_SLOT_FREE;
page->val[slot] = ASL_MSG_SLOT_FREE;
page->op[slot] = 0;
return _asl_msg_new_key_val_op(msg, key, val, op);
}
int
asl_msg_set_key_val_op(asl_msg_t *msg, const char *key, const char *val, uint32_t op)
{
char *special, buf[512];
uint32_t i, len;
int status;
special = NULL;
if (streq(key, ASL_KEY_LEVEL))
{
if (val == NULL) val = "7";
else if ((val[0] >= '0') && (val[0] <= '7') && (val[1] == '\0')) ;
else if (strcaseeq(val, ASL_STRING_EMERG)) val = "0";
else if (strcaseeq(val, ASL_STRING_ALERT)) val = "1";
else if (strcaseeq(val, ASL_STRING_CRIT)) val = "2";
else if (strcaseeq(val, ASL_STRING_ERR)) val = "3";
else if (strcaseeq(val, ASL_STRING_WARNING)) val = "4";
else if (strcaseeq(val, ASL_STRING_NOTICE)) val = "5";
else if (strcaseeq(val, ASL_STRING_INFO)) val = "6";
else if (strcaseeq(val, ASL_STRING_DEBUG)) val = "7";
else val = "7";
}
if ((streq(key, ASL_KEY_MSG)) && (val != NULL))
{
len = strlen(val);
i = len;
while ((i > 0) && (val[i - 1] == '\n')) i--;
if (i == 0) val = NULL;
else if (i < len)
{
if (i < sizeof(buf))
{
memcpy(buf, val, i);
buf[i] = 0;
val = (const char *)buf;
}
else
{
special = malloc(i + 1);
if (special == NULL) return -1;
memcpy(special, val, i);
special[i] = 0;
val = (const char *)special;
}
}
}
status = _asl_msg_set_kvo(msg, key, val, op);
if (special != NULL) free(special);
return status;
}
int
asl_msg_set_key_val(asl_msg_t *msg, const char *key, const char *val)
{
return asl_msg_set_key_val_op(msg, key, val, 0);
}
static void
_asl_msg_merge_key_val(asl_msg_t *msg, const char *key, const char *val)
{
uint32_t i, slot;
asl_msg_t *page;
if (msg == NULL) return;
if (key == NULL) return;
slot = IndexNull;
page = NULL;
i = _asl_msg_index(msg, key, &slot, &page);
if (i != IndexNull) return;
asl_msg_set_key_val_op(msg, key, val, 0);
}
asl_msg_t *
asl_msg_merge(asl_msg_t *target, asl_msg_t *msg)
{
uint32_t x, slot, op, isnew = 0;
const char *key, *val;
asl_msg_t *page;
if (msg == NULL) return target;
if (target == NULL)
{
isnew = 1;
target = asl_msg_new(ASL_TYPE_MSG);
}
for (x = _asl_msg_fetch_internal(msg, 0, &key, &val, &op, &page, &slot); x != IndexNull; x = _asl_msg_fetch_internal(msg, x, &key, &val, &op, &page, &slot))
{
if (isnew == 1) asl_msg_set_key_val_op(target, key, val, 0);
else _asl_msg_merge_key_val(target, key, val);
}
return target;
}
asl_msg_t *
asl_msg_copy(asl_msg_t *msg)
{
return asl_msg_merge(NULL, msg);
}
void
asl_msg_unset(asl_msg_t *msg, const char *key)
{
uint32_t i, slot;
asl_msg_t *page;
char *ext;
if (msg == NULL) return;
if (key == NULL) return;
slot = IndexNull;
page = NULL;
i = _asl_msg_index(msg, key, &slot, &page);
if (i == IndexNull) return;
if ((page->key[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
{
memcpy(&ext, page->data + (page->key[slot] & ASL_MSG_OFFSET_MASK), sizeof(char *));
free(ext);
}
if ((page->val[slot] & ASL_MSG_KV_MASK) == ASL_MSG_KV_EXTERN)
{
memcpy(&ext, page->data + (page->val[slot] & ASL_MSG_OFFSET_MASK), sizeof(char *));
free(ext);
}
page->key[slot] = ASL_MSG_SLOT_FREE;
page->val[slot] = ASL_MSG_SLOT_FREE;
page->op[slot] = 0;
page->count--;
}
int
asl_msg_lookup(asl_msg_t *msg, const char *key, const char **valout, uint32_t *opout)
{
uint32_t i, slot;
asl_msg_t *page;
slot = IndexNull;
page = NULL;
i = _asl_msg_index(msg, key, &slot, &page);
if (i == IndexNull) return -1;
if (valout != NULL) *valout = _asl_msg_slot_val(page, slot);
if (opout != NULL) *opout = page->op[slot];
return 0;
}
uint32_t
asl_msg_type(asl_msg_t *msg)
{
if (msg == NULL) return 0;
return msg->type;
}
uint32_t
asl_msg_count(asl_msg_t *msg)
{
uint32_t total;
total = 0;
for (; msg != NULL; msg = msg->next) total += msg->count;
return total;
}
static int
_asl_msg_equal(asl_msg_t *a, asl_msg_t *b)
{
uint32_t x, oa, ob;
const char *key, *va, *vb;
if (asl_msg_count(a) != asl_msg_count(b)) return 0;
key = NULL;
va = NULL;
oa = 0;
for (x = asl_msg_fetch(a, 0, &key, &va, &oa); x != IndexNull; x = asl_msg_fetch(a, x, &key, &va, &oa))
{
if (asl_msg_lookup(b, key, &vb, &ob) != 0) return 0;
if (strcmp(va, vb)) return 0;
if ((a->type == ASL_TYPE_QUERY) && (oa != ob)) return 0;
}
return 1;
}
static int
_asl_isanumber(const char *s)
{
int i;
if (s == NULL) return 0;
i = 0;
if ((s[0] == '-') || (s[0] == '+')) i = 1;
if (s[i] == '\0') return 0;
for (; s[i] != '\0'; i++)
{
if (!isdigit(s[i])) return 0;
}
return 1;
}
static int
_asl_msg_basic_test(uint32_t op, const char *q, const char *m, uint32_t n)
{
int cmp;
uint32_t t;
int64_t nq, nm;
int rflags;
regex_t rex;
t = op & ASL_QUERY_OP_TRUE;
if ((q == NULL) || (m == NULL)) return (t & ASL_QUERY_OP_NOT_EQUAL);
if (op & ASL_QUERY_OP_REGEX)
{
if ((t == ASL_QUERY_OP_GREATER) || (t == ASL_QUERY_OP_LESS)) return 0;
memset(&rex, 0, sizeof(regex_t));
rflags = REG_EXTENDED | REG_NOSUB;
if (op & ASL_QUERY_OP_CASEFOLD) rflags |= REG_ICASE;
if (regcomp(&rex, q, rflags) != 0) return (t & ASL_QUERY_OP_NOT_EQUAL);
cmp = regexec(&rex, m, 0, NULL, 0);
regfree(&rex);
if (t == ASL_QUERY_OP_NOT_EQUAL) return (cmp != 0);
return (cmp == 0);
}
if (op & ASL_QUERY_OP_NUMERIC)
{
if (_asl_isanumber(q) == 0) return (t == ASL_QUERY_OP_NOT_EQUAL);
if (_asl_isanumber(m) == 0) return (t == ASL_QUERY_OP_NOT_EQUAL);
nq = atoll(q);
nm = atoll(m);
switch (t)
{
case ASL_QUERY_OP_EQUAL: return (nm == nq);
case ASL_QUERY_OP_GREATER: return (nm > nq);
case ASL_QUERY_OP_GREATER_EQUAL: return (nm >= nq);
case ASL_QUERY_OP_LESS: return (nm < nq);
case ASL_QUERY_OP_LESS_EQUAL: return (nm <= nq);
case ASL_QUERY_OP_NOT_EQUAL: return (nm != nq);
default: return (t == ASL_QUERY_OP_NOT_EQUAL);
}
}
cmp = 0;
if (op & ASL_QUERY_OP_CASEFOLD)
{
if (n == 0) cmp = strcasecmp(m, q);
else cmp = strncasecmp(m, q, n);
}
else
{
if (n == 0) cmp = strcmp(m, q);
else cmp = strncmp(m, q, n);
}
switch (t)
{
case ASL_QUERY_OP_EQUAL: return (cmp == 0);
case ASL_QUERY_OP_GREATER: return (cmp > 0);
case ASL_QUERY_OP_GREATER_EQUAL: return (cmp >= 0);
case ASL_QUERY_OP_LESS: return (cmp < 0);
case ASL_QUERY_OP_LESS_EQUAL: return (cmp <= 0);
case ASL_QUERY_OP_NOT_EQUAL: return (cmp != 0);
}
return (t == ASL_QUERY_OP_NOT_EQUAL);
}
static int
_asl_msg_test_substring(uint32_t op, const char *q, const char *m)
{
uint32_t t, i, d, lm, lq, match, newop;
t = op & ASL_QUERY_OP_TRUE;
lm = 0;
if (m != NULL) lm = strlen(m);
lq = 0;
if (q != NULL) lq = strlen(q);
if (lq == 0) return (t & ASL_QUERY_OP_EQUAL);
if (lq > lm) return (t == ASL_QUERY_OP_NOT_EQUAL);
if ((t == ASL_QUERY_OP_GREATER) || (t == ASL_QUERY_OP_LESS)) return 0;
newop = op & 0xff0;
newop |= ASL_QUERY_OP_EQUAL;
match = 0;
d = lm - lq;
for (i = 0; i <= d; i++)
{
if (_asl_msg_basic_test(newop, q, m + i, lq) != 0)
{
if (t & ASL_QUERY_OP_EQUAL) return 1;
match++;
}
}
if (t & ASL_QUERY_OP_EQUAL) return 0;
return (match == 0);
}
static int
_asl_msg_test_prefix(uint32_t op, const char *q, const char *m)
{
uint32_t lm, lq, t;
t = op & ASL_QUERY_OP_TRUE;
lm = 0;
if (m != NULL) lm = strlen(m);
lq = 0;
if (q != NULL) lq = strlen(q);
if (lq == 0) return (t & ASL_QUERY_OP_EQUAL);
if (lq > lm) return (t == ASL_QUERY_OP_NOT_EQUAL);
return _asl_msg_basic_test(op, q, m, lq);
}
static int
_asl_msg_test_suffix(uint32_t op, const char *q, const char *m)
{
uint32_t lm, lq, d, t;
t = op & ASL_QUERY_OP_TRUE;
lm = 0;
if (m != NULL) lm = strlen(m);
lq = 0;
if (q != NULL) lq = strlen(q);
if (lq == 0) return (t & ASL_QUERY_OP_EQUAL);
if (lq > lm) return (t == ASL_QUERY_OP_NOT_EQUAL);
d = lm - lq;
return _asl_msg_basic_test(op, q, m + d, lq);
}
static int
_asl_msg_test_expression(uint32_t op, const char *q, const char *m)
{
uint32_t t;
t = op & ASL_QUERY_OP_TRUE;
if (t == ASL_QUERY_OP_TRUE) return 1;
if (op & ASL_QUERY_OP_PREFIX)
{
if (op & ASL_QUERY_OP_SUFFIX) return _asl_msg_test_substring(op, q, m);
return _asl_msg_test_prefix(op, q, m);
}
if (op & ASL_QUERY_OP_SUFFIX) return _asl_msg_test_suffix(op, q, m);
return _asl_msg_basic_test(op, q, m, 0);
}
static int
_asl_msg_test_time_expression(uint32_t op, const char *q, const char *m)
{
time_t tq, tm;
uint32_t t;
if ((op & ASL_QUERY_OP_PREFIX) || (op & ASL_QUERY_OP_SUFFIX) || (op & ASL_QUERY_OP_REGEX)) return _asl_msg_test_expression(op, q, m);
if ((q == NULL) || (m == NULL)) return _asl_msg_test_expression(op, q, m);
tq = asl_parse_time(q);
if (tq < 0) return _asl_msg_test_expression(op, q, m);
tm = asl_parse_time(m);
if (tm < 0) return _asl_msg_test_expression(op, q, m);
t = op & ASL_QUERY_OP_TRUE;
switch (t)
{
case ASL_QUERY_OP_FALSE:
{
return 0;
}
case ASL_QUERY_OP_EQUAL:
{
if (tm == tq) return 1;
return 0;
}
case ASL_QUERY_OP_GREATER:
{
if (tm > tq) return 1;
return 0;
}
case ASL_QUERY_OP_GREATER_EQUAL:
{
if (tm >= tq) return 1;
return 0;
}
case ASL_QUERY_OP_LESS:
{
if (tm < tq) return 1;
return 0;
}
case ASL_QUERY_OP_LESS_EQUAL:
{
if (tm <= tq) return 1;
return 0;
}
case ASL_QUERY_OP_NOT_EQUAL:
{
if (tm != tq) return 1;
return 0;
}
case ASL_QUERY_OP_TRUE:
{
return 1;
}
}
return 0;
}
static int
_asl_msg_test(asl_msg_t *q, asl_msg_t *m)
{
uint32_t i, t, x, op;
int cmp;
const char *kq, *vq, *vm;
kq = NULL;
vq = NULL;
op = 0;
for (x = asl_msg_fetch(q, 0, &kq, &vq, &op); x != IndexNull; x = asl_msg_fetch(q, x, &kq, &vq, &op))
{
vm = NULL;
i = asl_msg_lookup(m, kq, &vm, NULL);
t = op & ASL_QUERY_OP_TRUE;
if (t == ASL_QUERY_OP_TRUE)
{
if (i != 0) return 0;
continue;
}
if (t == ASL_QUERY_OP_FALSE)
{
if (i == 0) return 0;
continue;
}
if (i != 0)
{
if (t == ASL_QUERY_OP_NOT_EQUAL) continue;
return 0;
}
cmp = 1;
if (streq(kq, ASL_KEY_TIME))
{
cmp = _asl_msg_test_time_expression(op, vq, vm);
}
else
{
cmp = _asl_msg_test_expression(op, vq, vm);
}
if (cmp == 0) return 0;
}
return 1;
}
int
asl_msg_cmp(asl_msg_t *a, asl_msg_t *b)
{
if (a == NULL) return 0;
if (b == NULL) return 0;
if (a->type == b->type) return _asl_msg_equal(a, b);
if (a->type == ASL_TYPE_QUERY) return _asl_msg_test(a, b);
return _asl_msg_test(b, a);
}
static char *
_asl_time_string(const char *fmt, const char *str)
{
time_t tick, off;
struct tm stm;
char *ltime;
char *out;
char ltbuf[32];
out = NULL;
time_t min;
const char *p = fmt;
tick = 0;
if (str != NULL) tick = asl_parse_time(str);
if ((fmt == NULL) || (!strcasecmp(fmt, "lcl")) || (!strcasecmp(fmt, "local")))
{
ltime = ctime_r(&tick, ltbuf);
if (ltime == NULL) return NULL;
ltime[19] = '\0';
asprintf(&out, "%s", ltime + 4);
return out;
}
if ((!strcasecmp(fmt, "sec")) || (!strcasecmp(fmt, "raw")))
{
asprintf(&out, "%lu", tick);
return out;
}
if (!strcasecmp(fmt, "j"))
{
if (NULL == localtime_r(&tick, &stm)) return NULL;
asprintf(&out, "%d-%02d-%02d %02d:%02d:%02d", stm.tm_year + 1900, stm.tm_mon + 1, stm.tm_mday, stm.tm_hour, stm.tm_min, stm.tm_sec);
return out;
}
if ((!strcasecmp(fmt, "utc")) || (!strcasecmp(fmt, "zulu")))
{
if (NULL == gmtime_r(&tick, &stm)) return NULL;
asprintf(&out, "%d-%02d-%02d %02d:%02d:%02dZ", stm.tm_year + 1900, stm.tm_mon + 1, stm.tm_mday, stm.tm_hour, stm.tm_min, stm.tm_sec);
return out;
}
if ((fmt[1] == '\0') && (((fmt[0] >= 'a') && (fmt[0] <= 'z')) || ((fmt[0] >= 'A') && (fmt[0] <= 'Z'))))
{
char z = fmt[0];
if (z >= 'a') z -= 32;
if (z == 'Z') off = 0;
else if ((z >= 'A') && (z <= 'I')) off = ((z - 'A') + 1) * SEC_PER_HOUR;
else if ((z >= 'K') && (z <= 'M')) off = (z - 'A') * SEC_PER_HOUR;
else if ((z >= 'N') && (z <= 'Y')) off = ('M' - z) * SEC_PER_HOUR;
else return NULL;
}
else
{
if ((*p == '-') || (*p == '+')) p++;
if ((*p) >= '0' && (*p <= '9'))
{
off = atoi(p);
if (fmt[0] == '-') off *= -1;
off *= SEC_PER_HOUR;
p = strchr(p, ':');
if (p != NULL)
{
min = atoi(p + 1);
if (fmt[0] == '-') min *= -1;
min *= 60;
off += min;
}
}
else
{
return NULL;
}
}
tick += off;
memset(&stm, 0, sizeof (struct tm));
if (NULL == gmtime_r(&tick, &stm)) return NULL;
if ((fmt[0] >= 'A') && (fmt[0] <= 'Z'))
{
asprintf(&out, "%d-%02d-%02d %02d:%02d:%02d%c", stm.tm_year + 1900, stm.tm_mon + 1, stm.tm_mday, stm.tm_hour, stm.tm_min, stm.tm_sec, fmt[0]);
}
else if ((fmt[0] >= 'a') && (fmt[0] <= 'z'))
{
asprintf(&out, "%d-%02d-%02d %02d:%02d:%02d%c", stm.tm_year + 1900, stm.tm_mon + 1, stm.tm_mday, stm.tm_hour, stm.tm_min, stm.tm_sec, fmt[0] - 32);
}
else if ((fmt[0] >= '0') && (fmt[0] <= '9'))
{
asprintf(&out, "%d-%02d-%02d %02d:%02d:%02d+%s", stm.tm_year + 1900, stm.tm_mon + 1, stm.tm_mday, stm.tm_hour, stm.tm_min, stm.tm_sec, fmt);
}
else
{
asprintf(&out, "%d-%02d-%02d %02d:%02d:%02d%s", stm.tm_year + 1900, stm.tm_mon + 1, stm.tm_mday, stm.tm_hour, stm.tm_min, stm.tm_sec, fmt);
}
return out;
}
__private_extern__ asl_string_t *
asl_msg_to_string_raw(uint32_t encoding, asl_msg_t *msg, const char *tfmt)
{
uint32_t i, x, count;
char *vtime;
const char *key, *val;
asl_string_t *str;
if (msg == NULL) return NULL;
count = asl_msg_count(msg);
if (count == 0) return NULL;
str = asl_string_new(encoding);
if (str == NULL) return NULL;
key = NULL;
val = NULL;
i = 0;
for (x = asl_msg_fetch(msg, 0, &key, &val, NULL); x != IndexNull; x = asl_msg_fetch(msg, x, &key, &val, NULL))
{
if (key == NULL) continue;
if (i > 0) asl_string_append_char_no_encoding(str, ' ');
asl_string_append_char_no_encoding(str, '[');
asl_string_append_asl_key(str, key);
if (!strcmp(key, ASL_KEY_TIME))
{
asl_string_append_char_no_encoding(str, ' ');
vtime = NULL;
if (val != NULL) vtime = _asl_time_string(tfmt, val);
if (vtime != NULL)
{
asl_string_append_no_encoding(str, vtime);
free(vtime);
}
else
{
asl_string_append_char_no_encoding(str, '0');
}
}
else if (val != NULL)
{
asl_string_append_char_no_encoding(str, ' ');
asl_string_append(str, val);
}
asl_string_append_char_no_encoding(str, ']');
i++;
}
return str;
}
static asl_string_t *
_asl_string_append_asl_msg(asl_string_t *str, asl_msg_t *msg)
{
const char *key, *val;
uint32_t i, op, n;
if (msg == NULL) return str;
if (msg->type == ASL_TYPE_QUERY) asl_string_append(str, "Q ");
i = 0;
n = 0;
forever
{
key = NULL;
val = NULL;
i = asl_msg_fetch(msg, i, &key, &val, &op);
if (key != NULL)
{
if (n != 0) asl_string_append_char_no_encoding(str, ' ');
n++;
asl_string_append_char_no_encoding(str, '[');
if (msg->type == ASL_TYPE_QUERY)
{
asl_string_append_op(str, op);
asl_string_append_char_no_encoding(str, ' ');
}
asl_string_append_asl_key(str, key);
if (val != NULL)
{
asl_string_append_char_no_encoding(str, ' ');
asl_string_append(str, val);
}
asl_string_append_char_no_encoding(str, ']');
}
if (i == IndexNull) break;
}
return str;
}
char *
asl_msg_to_string(asl_msg_t *msg, uint32_t *len)
{
char *out;
asl_string_t *str = asl_string_new(ASL_ENCODE_ASL);
if (str == NULL) return NULL;
str = _asl_string_append_asl_msg(str, msg);
*len = asl_string_length(str);
out = asl_string_free_return_bytes(str);
return out;
}
static uint32_t
_asl_msg_op_from_string(char *o)
{
uint32_t op, i;
op = ASL_QUERY_OP_NULL;
if (o == NULL) return op;
for (i = 0; o[i] != '\0'; i++)
{
if (o[i] == '.') return ASL_QUERY_OP_NULL;
if (o[i] == 'C') op |= ASL_QUERY_OP_CASEFOLD;
if (o[i] == 'R') op |= ASL_QUERY_OP_REGEX;
if (o[i] == 'N') op |= ASL_QUERY_OP_NUMERIC;
if (o[i] == 'S') op |= ASL_QUERY_OP_SUBSTRING;
if (o[i] == 'A') op |= ASL_QUERY_OP_PREFIX;
if (o[i] == 'Z') op |= ASL_QUERY_OP_SUFFIX;
if (o[i] == '<') op |= ASL_QUERY_OP_LESS;
if (o[i] == '>') op |= ASL_QUERY_OP_GREATER;
if (o[i] == '=') op |= ASL_QUERY_OP_EQUAL;
if (o[i] == '!') op |= ASL_QUERY_OP_NOT_EQUAL;
if (o[i] == 'T') op |= ASL_QUERY_OP_TRUE;
}
return op;
}
static char *
_asl_msg_get_next_word(char **p, uint32_t *tt, uint32_t spacedel)
{
char *str, *out, c, oval;
uint32_t i, len, n, outlen;
*tt = TOKEN_NULL;
if (p == NULL) return NULL;
if (*p == NULL) return NULL;
if (**p == '\0') return NULL;
if (**p == ' ') (*p)++;
if (spacedel != 0)
{
while ((**p == ' ') || (**p == '\t')) (*p)++;
}
if (**p == '\0') return NULL;
if (**p == '\n') return NULL;
str = *p;
if (**p == '[')
{
*tt = TOKEN_OPEN;
(*p)++;
out = malloc(2);
if (out == NULL) return NULL;
out[0] = '[';
out[1] = '\0';
return out;
}
len = 0;
outlen = 0;
forever
{
c = str[len];
if (((spacedel != 0) && (c == ' ')) || (c == ']') || (c == '\0')) break;
if (c == '\\')
{
len++;
c = str[len];
if ((c == 'a') || (c == 'b') || (c == 't') || (c == 'n') || (c == 'v') || (c == 'f') || (c == 'r') || (c == 's') || (c == '[') || (c == '\\') || (c == ']'))
{
}
else if (c == '^')
{
if (str[++len] == '\0') return NULL;
}
else if (c == 'M')
{
if (str[++len] == '\0') return NULL;
if (str[++len] == '\0') return NULL;
}
else if ((c >= '0') && (c <= '3'))
{
if (str[++len] == '\0') return NULL;
if (str[++len] == '\0') return NULL;
}
else
{
return NULL;
}
}
len++;
outlen++;
}
(*p) += len;
if ((len == 0) && (**p == ']'))
{
*tt = TOKEN_CLOSE;
(*p)++;
out = malloc(2);
if (out == NULL) return NULL;
out[0] = ']';
out[1] = '\0';
return out;
}
*tt = TOKEN_INT;
out = malloc(outlen + 1);
if (out == NULL) return NULL;
n = 0;
for (i = 0; i < len; i++)
{
c = str[i];
if (c == '\\')
{
*tt = TOKEN_WORD;
i++;
c = str[i];
if (c == 'a')
{
out[n++] = '\a';
}
else if (c == 'b')
{
out[n++] = '\b';
}
else if (c == 't')
{
out[n++] = '\t';
}
else if (c == 'n')
{
out[n++] = '\n';
}
else if (c == 'v')
{
out[n++] = '\v';
}
else if (c == 'f')
{
out[n++] = '\f';
}
else if (c == 'r')
{
out[n++] = '\r';
}
else if (c == 's')
{
out[n++] = ' ';
}
else if (c == '[')
{
out[n++] = '[';
}
else if (c == '\\')
{
out[n++] = '\\';
}
else if (c == ']')
{
out[n++] = ']';
}
else if (c == '^')
{
i++;
if (str[i] == '?') out[n++] = 127;
else out[n++] = str[i] - 64;
}
else if (c == 'M')
{
i++;
c = str[i];
if (c == '^')
{
i++;
if (str[i] == '?') out[n++] = 255;
else out[n++] = str[i] + 64;
}
else if (c == '-')
{
i++;
out[n++] = str[i] + 128;
}
else
{
*tt = TOKEN_NULL;
free(out);
return NULL;
}
}
else if ((c >= '0') && (c <= '3'))
{
oval = (c - '0') * 64;
i++;
c = str[i];
if ((c < '0') || (c > '7'))
{
*tt = TOKEN_NULL;
free(out);
return NULL;
}
oval += ((c - '0') * 8);
i++;
c = str[i];
if ((c < '0') || (c > '7'))
{
*tt = TOKEN_NULL;
free(out);
return NULL;
}
oval += (c - '0');
out[n++] = oval;
}
else
{
*tt = TOKEN_NULL;
free(out);
return NULL;
}
}
else
{
if ((c < '0') || (c > '9')) *tt = TOKEN_WORD;
out[n++] = c;
}
}
out[n] = '\0';
return out;
}
asl_msg_t *
asl_msg_from_string(const char *buf)
{
uint32_t tt, type, op;
char *k, *v, *o, *p;
asl_msg_t *out;
if (buf == NULL) return NULL;
type = ASL_TYPE_MSG;
p = (char *)buf;
k = _asl_msg_get_next_word(&p, &tt, 1);
if (k == NULL) return NULL;
if (streq(k, "Q"))
{
type = ASL_TYPE_QUERY;
free(k);
k = _asl_msg_get_next_word(&p, &tt, 1);
}
else if (tt == TOKEN_INT)
{
free(k);
k = _asl_msg_get_next_word(&p, &tt, 1);
if (k == NULL) return NULL;
}
out = asl_msg_new(ASL_TYPE_MSG);
if (out == NULL) return NULL;
out->type = type;
while (k != NULL)
{
op = ASL_QUERY_OP_NULL;
if (tt != TOKEN_OPEN)
{
asl_msg_release(out);
return NULL;
}
free(k);
if (type == ASL_TYPE_QUERY)
{
o = _asl_msg_get_next_word(&p, &tt, 1);
if ((o == NULL) || (tt != TOKEN_WORD))
{
if (o != NULL) free(o);
asl_msg_release(out);
return NULL;
}
op = _asl_msg_op_from_string(o);
free(o);
}
k = _asl_msg_get_next_word(&p, &tt, 1);
if (tt == TOKEN_INT) tt = TOKEN_WORD;
if ((k == NULL) || (tt != TOKEN_WORD))
{
if (k != NULL) free(k);
asl_msg_release(out);
return NULL;
}
v = _asl_msg_get_next_word(&p, &tt, 0);
if (tt == TOKEN_INT) tt = TOKEN_WORD;
if (v == NULL)
{
asl_msg_set_key_val_op(out, k, NULL, op);
free(k);
break;
}
if (tt == TOKEN_CLOSE)
{
asl_msg_set_key_val_op(out, k, NULL, op);
}
else if (tt == TOKEN_WORD)
{
asl_msg_set_key_val_op(out, k, v, op);
}
else
{
if (k != NULL) free(k);
if (v != NULL) free(v);
asl_msg_release(out);
return NULL;
}
if (k != NULL) free(k);
if (v != NULL) free(v);
if (tt != TOKEN_CLOSE)
{
k = _asl_msg_get_next_word(&p, &tt, 1);
if (k == NULL) break;
if (tt != TOKEN_CLOSE)
{
asl_msg_release(out);
return NULL;
}
free(k);
}
k = _asl_msg_get_next_word(&p, &tt, 1);
if (k == NULL) break;
}
return out;
}
char *
asl_list_to_string(asl_search_result_t *list, uint32_t *len)
{
uint32_t i;
char tmp[16];
char *out;
asl_string_t *str = asl_string_new(ASL_ENCODE_ASL);
if (str == NULL) return NULL;
if (list == NULL) return NULL;
if (list->count == 0) return NULL;
if (list->msg == NULL) return NULL;
snprintf(tmp, sizeof(tmp), "%u", list->count);
asl_string_append(str, tmp);
asl_string_append_char_no_encoding(str, '\n');
for (i = 0; i < list->count; i++)
{
_asl_string_append_asl_msg(str, list->msg[i]);
asl_string_append_char_no_encoding(str, '\n');
}
*len = asl_string_length(str);
out = asl_string_free_return_bytes(str);
return out;
}
asl_search_result_t *
asl_list_from_string(const char *buf)
{
uint32_t i, n;
const char *p;
asl_search_result_t *out;
asl_msg_t *m;
if (buf == NULL) return NULL;
p = buf;
n = atoi(buf);
if (n == 0) return NULL;
out = (asl_search_result_t *)calloc(1, sizeof(asl_search_result_t));
if (out == NULL) return NULL;
out->msg = (asl_msg_t **)calloc(n, sizeof(asl_msg_t *));
if (out->msg == NULL)
{
free(out);
return NULL;
}
for (i = 0; i < n; i++)
{
p = strchr(p, '\n');
if (p == NULL)
{
aslresponse_free((aslresponse)out);
return NULL;
}
p++;
m = asl_msg_from_string(p);
if (m == NULL)
{
aslresponse_free((aslresponse)out);
return NULL;
}
out->msg[i] = (asl_msg_t *)m;
out->count += 1;
}
return out;
}
static const char *
_asl_level_string(int level)
{
if (level == ASL_LEVEL_EMERG) return ASL_STRING_EMERG;
if (level == ASL_LEVEL_ALERT) return ASL_STRING_ALERT;
if (level == ASL_LEVEL_CRIT) return ASL_STRING_CRIT;
if (level == ASL_LEVEL_ERR) return ASL_STRING_ERR;
if (level == ASL_LEVEL_WARNING) return ASL_STRING_WARNING;
if (level == ASL_LEVEL_NOTICE) return ASL_STRING_NOTICE;
if (level == ASL_LEVEL_INFO) return ASL_STRING_INFO;
if (level == ASL_LEVEL_DEBUG) return ASL_STRING_DEBUG;
return "unknown";
}
static asl_string_t *
_asl_string_append_value_for_key_format(asl_string_t *str, asl_msg_t *msg, char *kf, const char *tfmt)
{
uint32_t i, get_fmt;
char *key, *fmt;
const char *mval;
if (str == NULL) return NULL;
if (msg == NULL) return str;
if (kf == NULL) return str;
key = NULL;
fmt = NULL;
get_fmt = 0;
for (i = 0; kf[i] != '\0'; i++)
{
if (kf[i] == ')')
{
kf[i] = '\0';
get_fmt = 1;
}
else if (kf[i] != '(')
{
if (key == NULL) key = kf + i;
else if ((get_fmt == 1) && (fmt == NULL)) fmt = kf + i;
}
}
if (key == NULL) return str;
asl_msg_lookup(msg, key, &mval, NULL);
if (mval == NULL) return str;
if (!strcmp(key, ASL_KEY_TIME))
{
char *fval = NULL;
if (fmt == NULL)
{
fval = _asl_time_string(tfmt, mval);
}
else
{
fval = _asl_time_string(fmt, mval);
}
if (fval != NULL)
{
asl_string_append_no_encoding(str, fval);
free(fval);
}
else
{
asl_string_append_char_no_encoding(str, '0');
}
return str;
}
if (!strcmp(key, ASL_KEY_LEVEL))
{
if (fmt == NULL)
{
asl_string_append_no_encoding(str, mval);
}
else if (!strcmp(fmt, "str"))
{
mval = _asl_level_string(atoi(mval));
asl_string_append_no_encoding(str, mval);
}
else
{
asl_string_append_no_encoding(str, mval);
}
return str;
}
return asl_string_append(str, mval);
}
char *
asl_format_message(asl_msg_t *msg, const char *mfmt, const char *tfmt, uint32_t text_encoding, uint32_t *len)
{
char *out, *vtime, *k, c, skey[512];
const char *vhost, *vpid, *vsender, *vmessage, *vlevel, *vrefproc, *vrefpid, *v, *key, *val;
int i, j, l, mf, paren, oval, level;
uint32_t x, cursor;
asl_string_t *str;
uint8_t *b64;
out = NULL;
*len = 0;
if (msg == NULL) return NULL;
mf = MFMT_RAW;
if (mfmt == NULL) mf = MFMT_RAW;
else if (!strcmp(mfmt, ASL_MSG_FMT_RAW)) mf = MFMT_RAW;
else if (!strcmp(mfmt, ASL_MSG_FMT_STD)) mf = MFMT_STD;
else if (!strcmp(mfmt, ASL_MSG_FMT_BSD)) mf = MFMT_BSD;
else if (!strcmp(mfmt, ASL_MSG_FMT_XML)) mf = MFMT_XML;
else if (!strcmp(mfmt, ASL_MSG_FMT_MSG)) mf = MFMT_MSG;
else mf = MFMT_STR;
if (mf == MFMT_RAW)
{
str = asl_msg_to_string_raw(text_encoding, msg, tfmt);
asl_string_append_char_no_encoding(str, '\n');
*len = asl_string_length(str);
out = asl_string_free_return_bytes(str);
return out;
}
if (mf == MFMT_MSG)
{
vmessage = NULL;
if (asl_msg_lookup(msg, ASL_KEY_MSG, &vmessage, NULL) != 0) return NULL;
str = asl_string_new(text_encoding);
if (str == NULL) return NULL;
asl_string_append(str, vmessage);
asl_string_append_char_no_encoding(str, '\n');
*len = asl_string_length(str);
out = asl_string_free_return_bytes(str);
return out;
}
if ((mf == MFMT_STD) || (mf == MFMT_BSD))
{
v = NULL;
vhost = NULL;
vsender = NULL;
vpid = NULL;
vmessage = NULL;
vlevel = NULL;
vrefproc = NULL;
vrefpid = NULL;
asl_msg_lookup(msg, ASL_KEY_TIME, &v, NULL);
vtime = _asl_time_string(tfmt, v);
level = 7;
asl_msg_lookup(msg, ASL_KEY_LEVEL, &vlevel, NULL);
if (vlevel != NULL) level = atoi(vlevel);
asl_msg_lookup(msg, ASL_KEY_HOST, &vhost, NULL);
if (vhost == NULL) vhost = "unknown";
asl_msg_lookup(msg, ASL_KEY_SENDER, &vsender, NULL);
if (vsender == NULL) vsender = "unknown";
asl_msg_lookup(msg, ASL_KEY_PID, &vpid, NULL);
asl_msg_lookup(msg, ASL_KEY_MSG, &vmessage, NULL);
asl_msg_lookup(msg, ASL_KEY_REF_PROC, &vrefproc, NULL);
asl_msg_lookup(msg, ASL_KEY_REF_PID, &vrefpid, NULL);
str = asl_string_new(text_encoding);
if (str == NULL) return NULL;
if (vtime != NULL)
{
asl_string_append(str, vtime);
free(vtime);
}
else
{
asl_string_append_char_no_encoding(str, '0');
}
asl_string_append_char_no_encoding(str, ' ');
asl_string_append(str, vhost);
asl_string_append_char_no_encoding(str, ' ');
asl_string_append(str, vsender);
if ((vpid != NULL) && (strcmp(vpid, "-1")))
{
asl_string_append_char_no_encoding(str, '[');
asl_string_append(str, vpid);
asl_string_append_char_no_encoding(str, ']');
}
if ((vrefproc != NULL) || (vrefpid != NULL)) asl_string_append_no_encoding(str, " (");
if (vrefproc != NULL) asl_string_append(str, vrefproc);
if (vrefpid != NULL)
{
asl_string_append_char_no_encoding(str, '[');
asl_string_append(str, vrefpid);
asl_string_append_char_no_encoding(str, ']');
}
if ((vrefproc != NULL) || (vrefpid != NULL)) asl_string_append_char_no_encoding(str, ')');
if (mf == MFMT_STD)
{
asl_string_append_no_encoding(str, " <");
asl_string_append(str, _asl_level_string(level));
asl_string_append_char_no_encoding(str, '>');
}
asl_string_append_no_encoding(str, ": ");
if (vmessage != NULL) asl_string_append(str, vmessage);
asl_string_append_char_no_encoding(str, '\n');
*len = asl_string_length(str);
out = asl_string_free_return_bytes(str);
return out;
}
if (mf == MFMT_XML)
{
str = asl_string_new(text_encoding);
if (str == NULL) return NULL;
asl_string_append_char_no_encoding(str, '\t');
asl_string_append(str, "<dict>");
asl_string_append_char_no_encoding(str, '\n');
for (x = asl_msg_fetch(msg, 0, &key, &val, NULL); x != IndexNull; x = asl_msg_fetch(msg, x, &key, &val, NULL))
{
if (asl_is_utf8(key) == 1)
{
asl_string_append_xml_tag(str, "key", key);
if (!strcmp(key, ASL_KEY_TIME))
{
vtime = _asl_time_string(tfmt, val);
if (vtime != NULL)
{
asl_string_append_xml_tag(str, "string", vtime);
free(vtime);
}
else
{
asl_string_append_xml_tag(str, "string", "0");
}
}
else
{
if (asl_is_utf8(val) == 1) asl_string_append_xml_tag(str, "string", val);
else
{
b64 = asl_b64_encode((uint8_t *)val, strlen(val));
asl_string_append_xml_tag(str, "data", (char *)b64);
free(b64);
}
}
}
}
asl_string_append_char_no_encoding(str, '\t');
asl_string_append(str, "</dict>");
asl_string_append_char_no_encoding(str, '\n');
*len = asl_string_length(str);
out = asl_string_free_return_bytes(str);
return out;
}
str = asl_string_new(text_encoding);
if (str == NULL) return NULL;
x = strlen(mfmt);
if (x <= sizeof(skey))
{
k = skey;
}
else
{
k = malloc(x);
if (k == NULL) return NULL;
}
cursor = 0;
for (i = 0; mfmt[i] != '\0'; i++)
{
if (mfmt[i] == '$')
{
paren = 0;
for (j = i + 1; mfmt[j] != 0; j++)
{
if (mfmt[j] == '(')
{
paren++;
}
else if (mfmt[j] == ')')
{
if (paren > 0) paren--;
if (paren == 0)
{
j++;
break;
}
}
else if (((mfmt[j] == ' ') || (mfmt[j] == '\t')) && (paren == 0)) break;
}
l = j - (i + 1);
memcpy(k, mfmt+i+1, l);
k[l] = '\0';
_asl_string_append_value_for_key_format(str, msg, k, tfmt);
i = j - 1;
continue;
}
if (mfmt[i] == '\\')
{
i++;
if (mfmt[i] == '$') asl_string_append_char_no_encoding(str, '$');
else if (mfmt[i] == 'e') asl_string_append_char_no_encoding(str, '\e');
else if (mfmt[i] == 's') asl_string_append_char_no_encoding(str, ' ');
else if (mfmt[i] == 'a') asl_string_append_char_no_encoding(str, '\a');
else if (mfmt[i] == 'b') asl_string_append_char_no_encoding(str, '\b');
else if (mfmt[i] == 'f') asl_string_append_char_no_encoding(str, '\f');
else if (mfmt[i] == 'n') asl_string_append_char_no_encoding(str, '\n');
else if (mfmt[i] == 'r') asl_string_append_char_no_encoding(str, '\r');
else if (mfmt[i] == 't') asl_string_append_char_no_encoding(str, '\t');
else if (mfmt[i] == 'v') asl_string_append_char_no_encoding(str, '\v');
else if (mfmt[i] == '\'') asl_string_append_char_no_encoding(str, '\'');
else if (mfmt[i] == '\\') asl_string_append_char_no_encoding(str, '\\');
else if (isdigit(mfmt[i]))
{
oval = mfmt[i] - '0';
if (isdigit(mfmt[i+1]))
{
i++;
oval = (oval * 8) + (mfmt[i] - '0');
if (isdigit(mfmt[i+1]))
{
i++;
oval = (oval * 8) + (mfmt[i] - '0');
}
}
c = oval;
asl_string_append_char_no_encoding(str, c);
}
continue;
}
if (mfmt[i] == '\0') break;
asl_string_append_char_no_encoding(str, mfmt[i]);
}
if (k != skey) free(k);
asl_string_append_char_no_encoding(str, '\n');
*len = asl_string_length(str);
out = asl_string_free_return_bytes(str);
return out;
}
const char *
asl_key(aslmsg msg, uint32_t n)
{
uint32_t slot, i;
asl_msg_t *page;
i = 0;
for (page = (asl_msg_t *)msg; page != NULL; page = page->next)
{
for (slot = 0; slot < ASL_MSG_PAGE_SLOTS; slot++)
{
if (page->key[slot] != ASL_MSG_SLOT_FREE)
{
if (i == n) return _asl_msg_slot_key(page, slot);
i++;
}
}
}
return NULL;
}
aslmsg
asl_new(uint32_t type)
{
return (aslmsg)asl_msg_new(type);
}
int
asl_set(aslmsg msg, const char *key, const char *value)
{
return asl_msg_set_key_val_op((asl_msg_t *)msg, key, value, IndexNull);
}
int
asl_set_query(aslmsg msg, const char *key, const char *value, uint32_t op)
{
return asl_msg_set_key_val_op((asl_msg_t *)msg, key, value, op);
}
int
asl_unset(aslmsg msg, const char *key)
{
asl_msg_unset((asl_msg_t *)msg, key);
return 0;
}
const char *
asl_get(aslmsg msg, const char *key)
{
const char *val;
int status;
val = NULL;
status = asl_msg_lookup((asl_msg_t *)msg, key, &val, NULL);
if (status != 0) return NULL;
return val;
}
void
asl_free(aslmsg msg)
{
asl_msg_release((asl_msg_t *)msg);
}
aslmsg
aslresponse_next(aslresponse r)
{
asl_search_result_t *res;
asl_msg_t *m;
res = (asl_search_result_t *)r;
if (res == NULL) return NULL;
if (res->curr >= res->count) return NULL;
m = res->msg[res->curr];
res->curr++;
return (aslmsg)m;
}
void
aslresponse_free(aslresponse r)
{
asl_search_result_t *res;
uint32_t i;
res = (asl_search_result_t *)r;
if (res == NULL) return;
for (i = 0; i < res->count; i++) asl_msg_release(res->msg[i]);
free(res->msg);
free(res);
}