706 lines
14 KiB
C
706 lines
14 KiB
C
/*
|
|
* Copyright (C) 2018 Intel Corporation
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include <libxml/parser.h>
|
|
#include <libxml/tree.h>
|
|
#include <string.h>
|
|
#include "load_conf.h"
|
|
#include "event_queue.h"
|
|
#include "log_sys.h"
|
|
|
|
static void print(void)
|
|
{
|
|
int id, id2;
|
|
int i, j;
|
|
struct sender_t *sender;
|
|
struct trigger_t *trigger;
|
|
struct vm_t *vm;
|
|
struct log_t *log;
|
|
struct info_t *info;
|
|
struct crash_t *crash;
|
|
struct crash_t *crash_tmp;
|
|
char buf[512];
|
|
|
|
#define print_id_item(item, root, id) \
|
|
LOGD("%-8s(%d): %-15s:(%s)\n", #root, id, #item, root->item)
|
|
#define print_2id_item(item, root, id, tid) \
|
|
LOGD("%-8s(%d): %-15s(%d):(%s)\n", \
|
|
#root, id, #item, tid, root->item[tid])
|
|
for_each_sender(id, sender, conf) {
|
|
if (!sender)
|
|
continue;
|
|
print_id_item(name, sender, id);
|
|
print_id_item(outdir, sender, id);
|
|
print_id_item(maxcrashdirs, sender, id);
|
|
print_id_item(maxlines, sender, id);
|
|
print_id_item(spacequota, sender, id);
|
|
|
|
if (sender->uptime) {
|
|
print_id_item(uptime->name, sender, id);
|
|
print_id_item(uptime->path, sender, id);
|
|
print_id_item(uptime->frequency, sender, id);
|
|
print_id_item(uptime->eventhours, sender, id);
|
|
}
|
|
}
|
|
|
|
for_each_trigger(id, trigger, conf) {
|
|
if (!trigger)
|
|
continue;
|
|
print_id_item(name, trigger, id);
|
|
print_id_item(type, trigger, id);
|
|
print_id_item(path, trigger, id);
|
|
}
|
|
|
|
for_each_vm(id, vm, conf) {
|
|
if (!vm)
|
|
continue;
|
|
print_id_item(name, vm, id);
|
|
print_id_item(channel, vm, id);
|
|
print_id_item(interval, vm, id);
|
|
for (i = 0; i < VM_EVENT_TYPE_MAX; i++) {
|
|
if (vm->syncevent[i])
|
|
print_2id_item(syncevent, vm, id, i);
|
|
}
|
|
}
|
|
|
|
for_each_log(id, log, conf) {
|
|
if (!log)
|
|
continue;
|
|
print_id_item(name, log, id);
|
|
print_id_item(type, log, id);
|
|
print_id_item(lines, log, id);
|
|
print_id_item(path, log, id);
|
|
}
|
|
|
|
for_each_info(id, info, conf) {
|
|
if (!info)
|
|
continue;
|
|
print_id_item(name, info, id);
|
|
print_id_item(channel, info, id);
|
|
print_id_item(interval, info, id);
|
|
print_id_item(trigger->name, info, id);
|
|
for_each_log_collect(id2, log, info) {
|
|
if (!log)
|
|
continue;
|
|
LOGD("%-8s(%d): %-15s(%c):(%s)\n",
|
|
"info", id, "log", 'x', log->name);
|
|
}
|
|
}
|
|
|
|
for_each_crash(id, crash, conf) {
|
|
if (!crash)
|
|
continue;
|
|
|
|
print_id_item(name, crash, id);
|
|
memset(buf, 0, sizeof(*buf));
|
|
LOGD("%-8s(%d): properties: %s, %s\n", "crash", id,
|
|
is_root_crash(crash) ? "root" : "non-root",
|
|
is_leaf_crash(crash) ? "leaf" : "non-leaf");
|
|
sprintf(buf + strlen(buf), "%-8s(%d): children: ", "crash", id);
|
|
for_crash_children(crash_tmp, crash)
|
|
sprintf(buf + strlen(buf), "%s ", crash_tmp->name);
|
|
LOGD("%s\n", buf);
|
|
print_id_item(trigger->name, crash, id);
|
|
print_id_item(channel, crash, id);
|
|
print_id_item(interval, crash, id);
|
|
for (i = 0; i < CONTENT_MAX; i++)
|
|
if (crash->content[i])
|
|
print_2id_item(content, crash, id, i);
|
|
|
|
for (i = 0; i < EXPRESSION_MAX; i++)
|
|
for (j = 0; j < CONTENT_MAX; j++)
|
|
if (crash->mightcontent[i][j])
|
|
LOGD("%-8s(%d): %-15s(%d,%d):(%s)\n",
|
|
"crash", id, "mightcontent", i, j,
|
|
crash->mightcontent[i][j]);
|
|
|
|
for (i = 0; i < DATA_MAX; i++)
|
|
if (crash->data[i])
|
|
print_2id_item(data, crash, id, i);
|
|
}
|
|
}
|
|
|
|
static int get_prop_int(xmlNodePtr cur, const char *key, const int max)
|
|
{
|
|
xmlChar *prop;
|
|
int value;
|
|
|
|
prop = xmlGetProp(cur, (const xmlChar *)key);
|
|
if (!prop) {
|
|
LOGE("get prop (%s) failed\n", key);
|
|
return -1;
|
|
}
|
|
|
|
value = atoi((char *)prop);
|
|
xmlFree(prop);
|
|
|
|
if (value > max) {
|
|
LOGE("prop (%s) exceeds MAX (%d)\n", prop, max);
|
|
return -1;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
static int get_id_index(xmlNodePtr cur, const int max)
|
|
{
|
|
int value = get_prop_int(cur, "id", max);
|
|
|
|
if (value <= 0)
|
|
return -1;
|
|
|
|
/* array index = value - 1 */
|
|
return value - 1;
|
|
}
|
|
|
|
static int get_expid_index(xmlNodePtr cur, const int max)
|
|
{
|
|
int value = get_prop_int(cur, "expression", max);
|
|
|
|
if (value <= 0)
|
|
return -1;
|
|
|
|
/* array index = value - 1 */
|
|
return value - 1;
|
|
}
|
|
|
|
#define load_cur_content(cur, type, mem) \
|
|
(__extension__ \
|
|
({ \
|
|
xmlChar *load##mem; \
|
|
int _ret = -1; \
|
|
load##mem = xmlNodeGetContent(cur); \
|
|
if (load##mem) { \
|
|
type->mem = (char *)load##mem; \
|
|
_ret = 0; \
|
|
} \
|
|
_ret; \
|
|
}) \
|
|
)
|
|
|
|
#define load_cur_content_with_id(cur, type, mem, max) \
|
|
(__extension__ \
|
|
({ \
|
|
xmlChar *load##mem; \
|
|
int index; \
|
|
int _ret = -1; \
|
|
load##mem = xmlNodeGetContent(cur); \
|
|
if (load##mem) { \
|
|
index = get_id_index(cur, max); \
|
|
if (index != -1) { \
|
|
type->mem[index] = (char *)load##mem; \
|
|
_ret = 0; \
|
|
} \
|
|
} \
|
|
_ret; \
|
|
}) \
|
|
)
|
|
|
|
#define load_trigger(cur, event) \
|
|
(__extension__ \
|
|
({ \
|
|
xmlChar *content = xmlNodeGetContent(cur); \
|
|
event->trigger = get_trigger_by_name((char *)content); \
|
|
xmlFree(content); \
|
|
}) \
|
|
)
|
|
|
|
struct crash_t *get_crash_by_wd(int wd)
|
|
{
|
|
int id;
|
|
struct crash_t *crash;
|
|
|
|
for_each_crash(id, crash, conf) {
|
|
if (!crash)
|
|
continue;
|
|
|
|
if (crash->wd == wd)
|
|
return crash;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
struct uptime_t *get_uptime_by_wd(int wd)
|
|
{
|
|
int id;
|
|
struct uptime_t *ut;
|
|
struct sender_t *sender;
|
|
|
|
for_each_sender(id, sender, conf) {
|
|
if (!sender)
|
|
continue;
|
|
|
|
ut = sender->uptime;
|
|
if (ut->wd == wd)
|
|
return ut;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
enum event_type_t get_conf_by_wd(int wd, void **private)
|
|
{
|
|
void *conf;
|
|
|
|
conf = (void *)get_uptime_by_wd(wd);
|
|
if (conf) {
|
|
*private = conf;
|
|
return UPTIME;
|
|
}
|
|
|
|
conf = (void *)get_crash_by_wd(wd);
|
|
if (conf) {
|
|
*private = conf;
|
|
return CRASH;
|
|
}
|
|
|
|
return UNKNOWN;
|
|
|
|
}
|
|
|
|
int sender_id(const struct sender_t *s)
|
|
{
|
|
int id;
|
|
struct sender_t *sender;
|
|
|
|
for_each_sender(id, sender, conf) {
|
|
if (!sender)
|
|
continue;
|
|
|
|
if (s == sender)
|
|
return id;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
struct sender_t *get_sender_by_name(char *name)
|
|
{
|
|
int id;
|
|
struct sender_t *sender;
|
|
|
|
for_each_sender(id, sender, conf) {
|
|
if (!sender)
|
|
continue;
|
|
|
|
if (strcmp(name, sender->name) == 0)
|
|
return sender;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
struct trigger_t *get_trigger_by_name(char *name)
|
|
{
|
|
int id;
|
|
struct trigger_t *trigger;
|
|
|
|
for_each_trigger(id, trigger, conf) {
|
|
if (!trigger)
|
|
continue;
|
|
if (strcmp(name, trigger->name) == 0)
|
|
return trigger;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
struct log_t *get_log_by_name(char *name)
|
|
{
|
|
int id;
|
|
struct log_t *log;
|
|
|
|
for_each_log(id, log, conf) {
|
|
if (!log)
|
|
continue;
|
|
if (strcmp(name, log->name) == 0)
|
|
return log;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int crash_depth(struct crash_t *tcrash)
|
|
{
|
|
int id;
|
|
int level = 0;
|
|
struct crash_t *crash;
|
|
|
|
for_each_crash(id, crash, conf) {
|
|
if (!crash)
|
|
continue;
|
|
|
|
if (crash->channel == tcrash->channel &&
|
|
crash->trigger == tcrash->trigger &&
|
|
crash->level > level)
|
|
level = crash->level;
|
|
}
|
|
level = level - tcrash->level;
|
|
return level;
|
|
}
|
|
|
|
static int is_enable(xmlNodePtr cur)
|
|
{
|
|
xmlChar *prop;
|
|
int ret = 0;
|
|
|
|
prop = xmlGetProp(cur, (const xmlChar *)"enable");
|
|
if (prop) {
|
|
ret = !xmlStrcmp((const xmlChar *)"true", prop);
|
|
xmlFree(prop);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#define name_is(cur, key) \
|
|
(xmlStrcmp(cur->name, (const xmlChar *)key) == 0)
|
|
|
|
static int parse_info(xmlNodePtr cur, struct info_t *info)
|
|
{
|
|
int id;
|
|
int res = 0;
|
|
xmlChar *content;
|
|
|
|
cur = cur->xmlChildrenNode;
|
|
while (cur) {
|
|
if (name_is(cur, "name"))
|
|
res = load_cur_content(cur, info, name);
|
|
else if (name_is(cur, "trigger"))
|
|
load_trigger(cur, info);
|
|
else if (name_is(cur, "channel"))
|
|
res = load_cur_content(cur, info, channel);
|
|
else if (name_is(cur, "log")) {
|
|
id = get_id_index(cur, LOG_MAX);
|
|
if (id == -1)
|
|
return -1;
|
|
content = xmlNodeGetContent(cur);
|
|
info->log[id] = get_log_by_name((char *)content);
|
|
xmlFree(content);
|
|
}
|
|
|
|
if (res)
|
|
return -1;
|
|
|
|
cur = cur->next;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int parse_log(xmlNodePtr cur, struct log_t *log)
|
|
{
|
|
int res = 0;
|
|
|
|
cur = cur->xmlChildrenNode;
|
|
while (cur) {
|
|
if (name_is(cur, "name"))
|
|
res = load_cur_content(cur, log, name);
|
|
else if (name_is(cur, "type"))
|
|
res = load_cur_content(cur, log, type);
|
|
else if (name_is(cur, "path"))
|
|
res = load_cur_content(cur, log, path);
|
|
else if (name_is(cur, "lines"))
|
|
res = load_cur_content(cur, log, lines);
|
|
|
|
if (res)
|
|
return -1;
|
|
|
|
cur = cur->next;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int parse_crash(xmlNodePtr cur, struct crash_t *crash)
|
|
{
|
|
|
|
int id;
|
|
int expid;
|
|
int res = 0;
|
|
xmlChar *content;
|
|
|
|
cur = cur->xmlChildrenNode;
|
|
while (cur) {
|
|
if (name_is(cur, "name"))
|
|
res = load_cur_content(cur, crash, name);
|
|
else if (name_is(cur, "trigger"))
|
|
load_trigger(cur, crash);
|
|
else if (name_is(cur, "channel"))
|
|
res = load_cur_content(cur, crash, channel);
|
|
else if (name_is(cur, "content"))
|
|
res = load_cur_content_with_id(cur, crash,
|
|
content, CONTENT_MAX);
|
|
else if (name_is(cur, "log")) {
|
|
id = get_id_index(cur, LOG_MAX);
|
|
if (id == -1)
|
|
return -1;
|
|
|
|
content = xmlNodeGetContent(cur);
|
|
crash->log[id] = get_log_by_name((char *)content);
|
|
xmlFree(content);
|
|
} else if (name_is(cur, "data"))
|
|
res = load_cur_content_with_id(cur, crash,
|
|
data, DATA_MAX);
|
|
else if (name_is(cur, "mightcontent")) {
|
|
id = get_id_index(cur, CONTENT_MAX);
|
|
expid = get_expid_index(cur, EXPRESSION_MAX);
|
|
if (id == -1 || expid == -1)
|
|
return -1;
|
|
|
|
content = xmlNodeGetContent(cur);
|
|
crash->mightcontent[expid][id] = (char *)content;
|
|
}
|
|
|
|
if (res)
|
|
return -1;
|
|
|
|
cur = cur->next;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int parse_crashes(xmlNodePtr crashes)
|
|
{
|
|
int id;
|
|
int res;
|
|
xmlNodePtr cur;
|
|
struct crash_t *crash;
|
|
|
|
cur = crashes->xmlChildrenNode;
|
|
|
|
while (cur) {
|
|
if (is_enable(cur)) {
|
|
crash = malloc(sizeof(*crash));
|
|
if (!crash)
|
|
return -1;
|
|
|
|
res = get_prop_int(cur, "inherit", CRASH_MAX);
|
|
if (res < 0)
|
|
return -1;
|
|
|
|
id = res - 1;
|
|
if (id >= 0) {
|
|
memcpy(crash, conf.crash[id], sizeof(*crash));
|
|
crash->parents = conf.crash[id];
|
|
crash->level++;
|
|
TAILQ_INSERT_TAIL(&crash->parents->children,
|
|
crash, entries);
|
|
} else {
|
|
memset(crash, 0, sizeof(*crash));
|
|
}
|
|
id = get_id_index(cur, CRASH_MAX);
|
|
if (id == -1) {
|
|
free(crash);
|
|
return -1;
|
|
}
|
|
res = parse_crash(cur, crash);
|
|
if (res) {
|
|
free(crash);
|
|
return -1;
|
|
}
|
|
|
|
TAILQ_INIT(&crash->children);
|
|
conf.crash[id] = crash;
|
|
}
|
|
cur = cur->next;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int parse_vm(xmlNodePtr cur, struct vm_t *vm)
|
|
{
|
|
int res = 0;
|
|
|
|
cur = cur->xmlChildrenNode;
|
|
while (cur) {
|
|
if (name_is(cur, "name"))
|
|
res = load_cur_content(cur, vm, name);
|
|
else if (name_is(cur, "channel"))
|
|
res = load_cur_content(cur, vm, channel);
|
|
else if (name_is(cur, "interval"))
|
|
res = load_cur_content(cur, vm, interval);
|
|
else if (name_is(cur, "syncevent"))
|
|
res = load_cur_content_with_id(cur, vm,
|
|
syncevent,
|
|
VM_EVENT_TYPE_MAX);
|
|
|
|
if (res)
|
|
return -1;
|
|
|
|
cur = cur->next;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int parse_uptime(xmlNodePtr cur, struct sender_t *sender)
|
|
{
|
|
struct uptime_t *uptime;
|
|
int res = 0;
|
|
|
|
uptime = malloc(sizeof(*uptime));
|
|
if (!uptime)
|
|
return -1;
|
|
|
|
memset(uptime, 0, sizeof(*uptime));
|
|
cur = cur->xmlChildrenNode;
|
|
while (cur) {
|
|
if (name_is(cur, "name"))
|
|
res = load_cur_content(cur, uptime, name);
|
|
else if (name_is(cur, "frequency"))
|
|
res = load_cur_content(cur, uptime, frequency);
|
|
else if (name_is(cur, "eventhours"))
|
|
res = load_cur_content(cur, uptime, eventhours);
|
|
|
|
if (res)
|
|
return -1;
|
|
|
|
cur = cur->next;
|
|
}
|
|
res = asprintf(&uptime->path, "%s/uptime", sender->outdir);
|
|
if (res < 0) {
|
|
LOGE("build string failed\n");
|
|
return -1;
|
|
}
|
|
sender->uptime = uptime;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int parse_trigger(xmlNodePtr cur, struct trigger_t *trigger)
|
|
{
|
|
int res = 0;
|
|
|
|
cur = cur->xmlChildrenNode;
|
|
while (cur) {
|
|
if (name_is(cur, "name"))
|
|
res = load_cur_content(cur, trigger, name);
|
|
else if (name_is(cur, "type"))
|
|
res = load_cur_content(cur, trigger, type);
|
|
else if (name_is(cur, "path"))
|
|
res = load_cur_content(cur, trigger, path);
|
|
|
|
if (res)
|
|
return -1;
|
|
|
|
cur = cur->next;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int parse_sender(xmlNodePtr cur, struct sender_t *sender)
|
|
{
|
|
int res = 0;
|
|
|
|
cur = cur->xmlChildrenNode;
|
|
while (cur) {
|
|
if (name_is(cur, "name"))
|
|
res = load_cur_content(cur, sender, name);
|
|
else if (name_is(cur, "outdir"))
|
|
res = load_cur_content(cur, sender, outdir);
|
|
else if (name_is(cur, "maxcrashdirs"))
|
|
res = load_cur_content(cur, sender, maxcrashdirs);
|
|
else if (name_is(cur, "maxlines"))
|
|
res = load_cur_content(cur, sender, maxlines);
|
|
else if (name_is(cur, "spacequota"))
|
|
res = load_cur_content(cur, sender, spacequota);
|
|
else if (name_is(cur, "uptime"))
|
|
res = parse_uptime(cur, sender);
|
|
|
|
if (res)
|
|
return -1;
|
|
|
|
cur = cur->next;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define common_parse(node, mem, maxmem) \
|
|
(__extension__ \
|
|
({ \
|
|
int id; \
|
|
int _ret = 0; \
|
|
int res; \
|
|
struct mem##_t *mem; \
|
|
\
|
|
node = node->xmlChildrenNode; \
|
|
\
|
|
while (node) { \
|
|
if (is_enable(node)) { \
|
|
id = get_id_index(node, maxmem); \
|
|
if (id < 0) { \
|
|
_ret = -1; \
|
|
break; \
|
|
} \
|
|
\
|
|
mem = malloc(sizeof(*mem)); \
|
|
if (!mem) { \
|
|
_ret = -1; \
|
|
break; \
|
|
} \
|
|
memset(mem, 0, sizeof(*mem)); \
|
|
conf.mem[id] = mem; \
|
|
res = parse_##mem(node, mem); \
|
|
if (res) { \
|
|
free(mem); \
|
|
_ret = -1; \
|
|
break; \
|
|
} \
|
|
} \
|
|
node = node->next; \
|
|
} \
|
|
_ret; \
|
|
}) \
|
|
)
|
|
|
|
int load_conf(const char *path)
|
|
{
|
|
int res = 0;
|
|
xmlDocPtr doc;
|
|
xmlNodePtr cur, node;
|
|
|
|
doc = xmlParseFile(path);
|
|
if (!doc) {
|
|
LOGI("Parsing conf (%s) fail\n", path);
|
|
goto error;
|
|
}
|
|
|
|
cur = xmlDocGetRootElement(doc);
|
|
if (!cur) {
|
|
LOGE("Get root (%s) fail\n", path);
|
|
goto free;
|
|
}
|
|
|
|
cur = cur->xmlChildrenNode;
|
|
while ((node = cur)) {
|
|
if (name_is(node, "senders"))
|
|
res = common_parse(node, sender, SENDER_MAX);
|
|
else if (name_is(node, "triggers"))
|
|
res = common_parse(node, trigger, TRIGGER_MAX);
|
|
else if (name_is(node, "vms"))
|
|
res = common_parse(node, vm, VM_MAX);
|
|
else if (name_is(node, "crashes"))
|
|
res = parse_crashes(node);
|
|
else if (name_is(node, "logs"))
|
|
res = common_parse(node, log, LOG_MAX);
|
|
else if (name_is(node, "infos"))
|
|
res = common_parse(node, info, INFO_MAX);
|
|
|
|
if (res)
|
|
goto free;
|
|
|
|
cur = cur->next;
|
|
}
|
|
print();
|
|
xmlFreeDoc(doc);
|
|
return 0;
|
|
free:
|
|
xmlFreeDoc(doc);
|
|
error:
|
|
return -1;
|
|
}
|