tools: acrn-crashlog: configuration module of acrnprobe

To show the relationship between configuration items more clearly,
acrnprobe chose xml as its configuration file format.
This file provides functions to parse configuration and load them
into global variable conf.

Signed-off-by: Liu Xinwu <xinwu.liu@intel.com>
Reviewed-by: Zhang Yanmin <yanmin.zhang@intel.com>
Reviewed-by: Liu Chuansheng <chuansheng.liu@intel.com>
Reviewed-by: Zhao Yakui <yakui.zhao@intel.com>
Reviewed-by: Geoffroy Van Cutsem <geoffroy.vancutsem@intel.com>
Acked-by: Eddie Dong <Eddie.dong@intel.com>
This commit is contained in:
Liu Xinwu 2018-05-09 17:10:53 +08:00 committed by lijinxia
parent e86da09974
commit a35ef1aa90
4 changed files with 768 additions and 3 deletions

View File

@ -1,7 +1,7 @@
BASEDIR := $(shell pwd)
LIBS = -lpthread -lxml2 -lcrypto -lrt -lsystemd -ltelemetry
INCLUDE += -I $(BASEDIR)/include
INCLUDE += -I $(BASEDIR)/include -I /usr/include/libxml2
CFLAGS += $(INCLUDE)
CFLAGS += -g -O0 -std=gnu11
CFLAGS += -ffunction-sections -fdata-sections

View File

@ -6,6 +6,33 @@
#ifndef __EVENT_QUEUE_H__
#define __EVENT_QUEUE_H__
#include <sys/queue.h>
enum event_type_t {
CRASH,
INFO,
UPTIME,
HEART_BEAT,
REBOOT,
VM,
UNKNOWN
};
__extension__
struct event_t {
int watchfd;
enum event_type_t event_type;
char *channel;
void *private;
TAILQ_ENTRY(event_t) entries;
/* dir to storage logs */
char *dir;
int len;
char path[0]; /* keep this at tail*/
};
void init_event_queue(void);
#endif

View File

@ -6,7 +6,76 @@
#ifndef __LOAD_CONF_H__
#define __LOAD_CONF_H__
#include <stdio.h>
#include <sys/queue.h>
#include <openssl/sha.h>
#include "event_queue.h"
#define CONTENT_MAX 10
#define EXPRESSION_MAX 5
#define LOG_MAX 20
#define TRIGGER_MAX 20
#define SENDER_MAX 3
#define DATA_MAX 3
#define CRASH_MAX 20
#define INFO_MAX 20
#define VM_MAX 4
#define VM_EVENT_TYPE_MAX 20
struct trigger_t {
char *name;
char *type;
char *path;
};
struct vm_t {
char *name;
char *channel;
char *interval;
char *syncevent[VM_EVENT_TYPE_MAX];
int online;
unsigned long history_size[SENDER_MAX];
char last_synced_line_key[SENDER_MAX][SHA_DIGEST_LENGTH + 1];
};
struct log_t {
char *name;
char *type;
char *path;
char *lines;
void (*get)(struct log_t *, void *);
};
struct crash_t {
char *name;
char *channel;
char *interval;
struct trigger_t *trigger;
char *content[CONTENT_MAX];
char *mightcontent[EXPRESSION_MAX][CONTENT_MAX];
struct log_t *log[LOG_MAX];
char *data[DATA_MAX];
struct crash_t *parents;
TAILQ_ENTRY(crash_t) entries;
TAILQ_HEAD(, crash_t) children;
int wd;
int level;
struct crash_t *(*reclassify)(struct crash_t *, char*, char**, char**,
char**);
};
struct info_t {
char *name;
char *channel;
char *interval;
struct trigger_t *trigger;
struct log_t *log[LOG_MAX];
};
struct uptime_t {
char *name;
@ -18,11 +87,25 @@ struct uptime_t {
};
struct sender_t {
char *name;
char *outdir;
char *maxcrashdirs;
char *maxlines;
char *spacequota;
struct uptime_t *uptime;
void (*send)(struct event_t *);
char *log_vmrecordid;
int sw_updated; /* each sender has their own record */
};
struct conf_t {
struct sender_t *sender[SENDER_MAX];
struct vm_t *vm[VM_MAX];
struct trigger_t *trigger[TRIGGER_MAX];
struct log_t *log[LOG_MAX];
struct crash_t *crash[CRASH_MAX];
struct info_t *info[INFO_MAX];
};
struct conf_t conf;
@ -32,6 +115,98 @@ struct conf_t conf;
id < SENDER_MAX; \
id++, sender = conf.sender[id])
#define for_each_trigger(id, trigger, conf) \
for (id = 0, trigger = conf.trigger[0]; \
id < TRIGGER_MAX; \
id++, trigger = conf.trigger[id])
#define for_each_vm(id, vm, conf) \
for (id = 0, vm = conf.vm[0]; \
id < VM_MAX; \
id++, vm = conf.vm[id])
#define for_each_syncevent_vm(id, event, vm) \
for (id = 0, event = vm->syncevent[0]; \
id < VM_EVENT_TYPE_MAX; \
id++, event = vm->syncevent[id])
#define for_each_info(id, info, conf) \
for (id = 0, info = conf.info[0]; \
id < INFO_MAX; \
id++, info = conf.info[id])
#define for_each_log(id, log, conf) \
for (id = 0, log = conf.log[0]; \
id < LOG_MAX; \
id++, log = conf.log[id])
#define for_each_crash(id, crash, conf) \
for (id = 0, crash = conf.crash[0]; \
id < CRASH_MAX; \
id++, crash = conf.crash[id])
#define for_each_log_collect(id, log, type) \
for (id = 0, log = type->log[0]; \
id < LOG_MAX; \
id++, log = type->log[id])
#define for_each_content_crash(id, content, crash) \
for (id = 0, content = crash->content[0]; \
id < CONTENT_MAX; \
id++, content = crash->content[id])
#define for_each_content_expression(id, content, exp) \
for (id = 0, content = exp[0]; \
id < CONTENT_MAX; \
id++, content = exp[id])
#define exp_valid(exp) \
(__extension__ \
({ \
int _ret = 0; \
int _id; \
char *content; \
for_each_content_expression(_id, content, exp) { \
if (content) \
_ret = 1; \
} \
_ret; \
}) \
)
#define for_each_expression_crash(id, exp, crash) \
for (id = 0, exp = crash->mightcontent[0]; \
id < EXPRESSION_MAX; \
id++, exp = crash->mightcontent[id])
#define for_crash_children(crash, tcrash) \
TAILQ_FOREACH(crash, &tcrash->children, entries)
#define is_leaf_crash(crash) \
(crash && TAILQ_EMPTY(&crash->children))
#define is_root_crash(crash) \
(crash && crash->parents == NULL)
#define to_collect_logs(type) \
(__extension__ \
({ \
int _id; \
int _ret = 0; \
for (_id = 0; _id < LOG_MAX; _id++) \
if (type->log[_id]) \
_ret = 1; \
_ret; \
}) \
)
int load_conf(char *path);
struct trigger_t *get_trigger_by_name(char *name);
struct log_t *get_log_by_name(char *name);
int sender_id(struct sender_t *sender);
struct sender_t *get_sender_by_name(char *name);
enum event_type_t get_conf_by_wd(int wd, void **private);
struct crash_t *get_crash_by_wd(int wd);
int crash_depth(struct crash_t *tcrash);
#endif

View File

@ -3,9 +3,572 @@
* 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"
int load_conf(char *path __attribute__((unused)))
static void print(void)
{
return 0;
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, char *key)
{
xmlChar *prop;
int ret = 0;
prop = xmlGetProp(cur, (const xmlChar *)key);
if (prop) {
ret = atoi((char *)prop);
xmlFree(prop);
}
return ret;
}
static int get_id_index(xmlNodePtr cur)
{
return get_prop_int(cur, "id") - 1;
}
#define load_cur_content(cur, type, mem) \
(__extension__ \
({ \
xmlChar *load##mem; \
load##mem = xmlNodeGetContent(cur); \
if (load##mem) \
type->mem = (char *)load##mem; \
}) \
)
#define load_cur_content_with_id(cur, type, mem) \
(__extension__ \
({ \
xmlChar *load##mem; \
load##mem = xmlNodeGetContent(cur); \
if (load##mem) \
type->mem[get_id_index(cur)] = (char *)load##mem; \
}) \
)
#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(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;
}
static int get_inherit_index(xmlNodePtr cur)
{
return get_prop_int(cur, "inherit") - 1;
}
#define name_is(cur, key) \
(xmlStrcmp(cur->name, (const xmlChar *)key) == 0)
static void parse_info(xmlNodePtr cur, struct info_t *info)
{
int id;
xmlChar *content;
cur = cur->xmlChildrenNode;
while (cur) {
if (name_is(cur, "name"))
load_cur_content(cur, info, name);
else if (name_is(cur, "trigger"))
load_trigger(cur, info);
else if (name_is(cur, "channel"))
load_cur_content(cur, info, channel);
else if (name_is(cur, "log")) {
id = get_id_index(cur);
content = xmlNodeGetContent(cur);
info->log[id] = get_log_by_name((char *)content);
xmlFree(content);
}
cur = cur->next;
}
}
static void parse_log(xmlNodePtr cur, struct log_t *log)
{
cur = cur->xmlChildrenNode;
while (cur) {
if (name_is(cur, "name"))
load_cur_content(cur, log, name);
else if (name_is(cur, "type"))
load_cur_content(cur, log, type);
else if (name_is(cur, "path"))
load_cur_content(cur, log, path);
else if (name_is(cur, "lines"))
load_cur_content(cur, log, lines);
cur = cur->next;
}
}
static void parse_crash(xmlNodePtr cur, struct crash_t *crash)
{
int id;
int expression;
xmlChar *content;
cur = cur->xmlChildrenNode;
while (cur) {
if (name_is(cur, "name"))
load_cur_content(cur, crash, name);
else if (name_is(cur, "trigger"))
load_trigger(cur, crash);
else if (name_is(cur, "channel"))
load_cur_content(cur, crash, channel);
else if (name_is(cur, "content"))
load_cur_content_with_id(cur, crash, content);
else if (name_is(cur, "log")) {
id = get_id_index(cur);
content = xmlNodeGetContent(cur);
crash->log[id] = get_log_by_name((char *)content);
xmlFree(content);
} else if (name_is(cur, "data"))
load_cur_content_with_id(cur, crash, data);
else if (name_is(cur, "mightcontent")) {
id = get_id_index(cur);
expression = get_prop_int(cur, "expression") - 1;
content = xmlNodeGetContent(cur);
crash->mightcontent[expression][id] = (char *)content;
}
cur = cur->next;
}
}
static void parse_crashes(xmlNodePtr crashes)
{
int id;
xmlNodePtr cur;
struct crash_t *crash;
cur = crashes->xmlChildrenNode;
while (cur) {
if (is_enable(cur)) {
crash = malloc(sizeof(*crash));
id = get_inherit_index(cur);
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));
}
TAILQ_INIT(&crash->children);
id = get_id_index(cur);
conf.crash[id] = crash;
parse_crash(cur, crash);
}
cur = cur->next;
}
}
static void parse_vm(xmlNodePtr cur, struct vm_t *vm)
{
cur = cur->xmlChildrenNode;
while (cur) {
if (name_is(cur, "name"))
load_cur_content(cur, vm, name);
else if (name_is(cur, "channel"))
load_cur_content(cur, vm, channel);
else if (name_is(cur, "interval"))
load_cur_content(cur, vm, interval);
else if (name_is(cur, "syncevent"))
load_cur_content_with_id(cur, vm, syncevent);
cur = cur->next;
}
}
static void parse_uptime(xmlNodePtr cur, struct sender_t *sender)
{
struct uptime_t *uptime;
int ret;
uptime = malloc(sizeof(*uptime));
memset(uptime, 0, sizeof(*uptime));
cur = cur->xmlChildrenNode;
while (cur) {
if (name_is(cur, "name"))
load_cur_content(cur, uptime, name);
else if (name_is(cur, "frequency"))
load_cur_content(cur, uptime, frequency);
else if (name_is(cur, "eventhours"))
load_cur_content(cur, uptime, eventhours);
cur = cur->next;
}
ret = asprintf(&uptime->path, "%s/uptime", sender->outdir);
if (ret < 0) {
LOGE("build string failed\n");
exit(EXIT_FAILURE);
}
sender->uptime = uptime;
}
static void parse_trigger(xmlNodePtr cur, struct trigger_t *trigger)
{
cur = cur->xmlChildrenNode;
while (cur) {
if (name_is(cur, "name"))
load_cur_content(cur, trigger, name);
else if (name_is(cur, "type"))
load_cur_content(cur, trigger, type);
else if (name_is(cur, "path"))
load_cur_content(cur, trigger, path);
cur = cur->next;
}
}
static void parse_sender(xmlNodePtr cur, struct sender_t *sender)
{
cur = cur->xmlChildrenNode;
while (cur) {
if (name_is(cur, "name"))
load_cur_content(cur, sender, name);
else if (name_is(cur, "outdir"))
load_cur_content(cur, sender, outdir);
else if (name_is(cur, "maxcrashdirs"))
load_cur_content(cur, sender, maxcrashdirs);
else if (name_is(cur, "maxlines"))
load_cur_content(cur, sender, maxlines);
else if (name_is(cur, "spacequota"))
load_cur_content(cur, sender, spacequota);
else if (name_is(cur, "uptime"))
parse_uptime(cur, sender);
cur = cur->next;
}
}
#define common_parse(node, mem) \
(__extension__ \
({ \
int id; \
struct mem##_t *mem; \
\
node = node->xmlChildrenNode; \
\
while (node) { \
if (is_enable(node)) { \
mem = malloc(sizeof(*mem)); \
memset(mem, 0, sizeof(*mem)); \
id = get_id_index(node); \
conf.mem[id] = mem; \
parse_##mem(node, mem); \
} \
node = node->next; \
} \
}) \
)
int load_conf(char *path)
{
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"))
common_parse(node, sender);
else if (name_is(node, "triggers"))
common_parse(node, trigger);
else if (name_is(node, "vms"))
common_parse(node, vm);
else if (name_is(node, "crashes"))
parse_crashes(node);
else if (name_is(node, "logs"))
common_parse(node, log);
else if (name_is(node, "infos"))
common_parse(node, info);
cur = cur->next;
}
print();
xmlFreeDoc(doc);
return 0;
free:
xmlFreeDoc(doc);
error:
return -1;
}