acrn-hypervisor/misc/tools/acrn-crashlog/acrnprobe/sender.c
Terry Zou a9c38a5cfb HV:Acrn-hypvervisor Root Directory Clean-up and create misc/ folder for Acrn daemons, services and tools.
This patch is to clean-up acrn-hypervisor root directory, targt only 5 folders under acrn-hypervisor:1.hypervisor,2.devicemodel,3.misc,4.doc,5.build

Tracked-On: #3482
Signed-off-by: Terry Zou <terry.zou@intel.com>
Acked-by: Eddie Dong <eddie.dong@intel.com>
2019-07-29 22:58:24 +08:00

1123 lines
24 KiB
C

/*
* Copyright (C) 2018 Intel Corporation
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <limits.h>
#include "fsutils.h"
#include "strutils.h"
#include "cmdutils.h"
#include "load_conf.h"
#include "sender.h"
#include "probeutils.h"
#include "android_events.h"
#include "history.h"
#include "property.h"
#include "startupreason.h"
#include "log_sys.h"
#include "loop.h"
#ifdef HAVE_TELEMETRICS_CLIENT
#include "telemetry.h"
#define CRASH_SEVERITY 4
#define INFO_SEVERITY 2
#endif
static int crashlog_check_space(void)
{
struct sender_t *crashlog = get_sender_by_name("crashlog");
int quota;
int cfg_size;
if (!crashlog)
return -1;
if (cfg_atoi(crashlog->spacequota, crashlog->spacequota_len,
&quota) == -1)
return -1;
if (!space_available(crashlog->outdir, quota))
return -1;
if (cfg_atoi(crashlog->foldersize, crashlog->foldersize_len,
&cfg_size) == -1)
return -1;
if (crashlog->outdir_blocks_size/MB >= (size_t)cfg_size) {
LOGD("the total blocks size (%zu) meets the quota (%zu)\n",
crashlog->outdir_blocks_size/MB, (size_t)cfg_size);
return -1;
}
return 0;
}
static int log_grows(char *dir, size_t len)
{
size_t add;
struct sender_t *crashlog = get_sender_by_name("crashlog");
if (!crashlog)
return -1;
if (dir_blocks_size(dir, len, &add) == -1) {
LOGE("failed to check outdir size\n");
return -1;
}
add += 4 * KB;
crashlog->outdir_blocks_size += add;
LOGD("log size + %zu = %zu\n", add, crashlog->outdir_blocks_size);
return 0;
}
static int cal_log_filepath(char **out, const struct log_t *log,
const char *srcname, const char *desdir)
{
const char *filename;
int need_timestamp = 0;
int hours;
char timebuf[UPTIME_SIZE];
if (!out || !log || !desdir)
return -1;
if (is_ac_filefmt(log->path))
filename = srcname;
else
filename = log->name;
if (!filename)
return -1;
if (!strcmp(log->type, "cmd") || log->lines)
need_timestamp = 1;
if (need_timestamp) {
if (get_uptime_string(timebuf, &hours) == -1)
return -1;
return asprintf(out, "%s/%s_%s", desdir, filename, timebuf);
}
return asprintf(out, "%s/%s", desdir, filename);
}
/* get_log_file_* only used to copy regular file which can be mmaped */
static void get_log_file_complete(const char *despath, const char *srcpath)
{
const int ret = do_copy_tail(srcpath, despath, 0);
if (ret < 0) {
LOGE("copy (%s) failed, error (%s)\n", srcpath,
strerror(errno));
}
}
static void get_log_file_tail(const char *despath, const char *srcpath,
const int lines)
{
char *start;
int start_line;
int file_lines;
struct mm_file_t *mfile;
int ret;
mfile = mmap_file(srcpath);
if (!mfile) {
LOGE("mmap (%s) failed, error (%s)\n", srcpath,
strerror(errno));
return;
}
file_lines = mm_count_lines(mfile);
if (file_lines <= 0) {
LOGW("get lines (%s, %d) failed\n", mfile->path, file_lines);
goto unmap;
}
start_line = MAX(file_lines - lines, 0) + 1;
start = mm_get_line(mfile, start_line);
ret = overwrite_file(despath, start);
if (ret < 0) {
LOGE("create file with (%s, %p) failed, error (%s)\n",
despath, start, strerror(errno));
goto unmap;
}
unmap:
unmap_file(mfile);
}
static void get_log_file(const char *despath, const char *srcpath,
int lines)
{
if (lines > 0)
get_log_file_tail(despath, srcpath, lines);
else
get_log_file_complete(despath, srcpath);
}
static void get_log_node(const char *despath, const char *nodepath,
size_t sizelimit)
{
const int res = do_copy_limit(nodepath, despath, sizelimit);
if (res < 0) {
LOGE("copy (%s) failed, error (%s)\n", nodepath,
strerror(errno));
}
}
static void get_log_cmd(const char *despath, const char *cmd)
{
const int res = exec_out2file(despath, cmd);
if (res)
LOGE("get_log_by_cmd exec %s returns (%d)\n", cmd, res);
}
static void get_log_by_type(const char *despath, const struct log_t *log,
const char *srcpath)
{
if (!despath || !log || !srcpath)
return;
if (!strcmp("file", log->type)) {
int lines;
if (!log->lines)
lines = 0;
else
if (cfg_atoi(log->lines, log->lines_len, &lines) == -1)
return;
get_log_file(despath, srcpath, lines);
} else if (!strcmp("node", log->type)) {
int size;
if (!log->sizelimit)
size = 0;
else
if (cfg_atoi(log->sizelimit, log->sizelimit_len,
&size) == -1)
return;
get_log_node(despath, srcpath, (size_t)(size * 1024 * 1024));
}
else if (!strcmp("cmd", log->type))
get_log_cmd(despath, srcpath);
if (log->deletesource && !strcmp("true", log->deletesource))
remove(srcpath);
}
#ifdef HAVE_TELEMETRICS_CLIENT
static int telemd_send_data(char *payload, char *eventid, uint32_t severity,
char *class)
{
int res;
struct telem_ref *handle = NULL;
const uint32_t version = 1;
res = tm_create_record(&handle, severity, class, version);
if (res < 0) {
LOGE("failed to create record: %s\n",
strerror(-res));
goto fail;
}
/* eventid with 32 character length */
if (eventid) {
res = tm_set_event_id(handle, eventid);
if (res < 0) {
LOGE("failed to set eventid: %s\n", strerror(-res));
goto free;
}
}
res = tm_set_payload(handle, payload);
if (res < 0) {
LOGE("failed to set payload: %s\n", strerror(-res));
goto free;
}
res = tm_send_record(handle);
if (res < 0) {
LOGE("failed to send record: %s\n", strerror(-res));
goto free;
}
tm_free_record(handle);
return 0;
free:
tm_free_record(handle);
fail:
return -1;
}
static void telemd_get_log(const char *dir, char *eventid,
uint32_t severity, char *class)
{
char *files[512];
char *msg;
int count;
int i;
if (!dir)
goto send_nologs;
/* send logs */
count = lsdir(dir, files, ARRAY_SIZE(files));
if (count < 0) {
LOGE("lsdir (%s) failed, error (%s)\n", dir, strerror(-count));
return;
}
if (count > 2) {
for (i = 0; i < count; i++) {
if (strstr(files[i], "/.") || strstr(files[i], "/.."))
continue;
telemd_send_data(files[i], eventid, severity, class);
}
while (count > 0)
free(files[--count]);
return;
} else if (count == 2) {
while (count > 0)
free(files[--count]);
}
send_nologs:
if (asprintf(&msg, "no logs provided, check probe's log.") == -1) {
LOGE("failed to generate msg, out of memory\n");
return;
}
telemd_send_data(msg, eventid, severity, class);
free(msg);
}
#endif
static void crashlog_get_log(struct log_t *log, void *data)
{
unsigned long long start, end;
int spent;
int res;
char *des;
char *desdir = (char *)data;
start = get_uptime();
if (is_ac_filefmt(log->path)) {
int i;
char **files;
char *name;
const int count = config_fmt_to_files(log->path, &files);
if (count < 0) {
LOGE("parse config format (%s) failed\n", log->path);
return;
}
if (!count) {
LOGW("no logs found for (%s)\n", log->name);
return;
}
for (i = 0; i < count; i++) {
name = strrchr(files[i], '/') + 1;
if (name == (char *)1) {
LOGE("invalid path (%s) in log (%s)", files[i],
log->name);
continue;
}
res = cal_log_filepath(&des, log, name, desdir);
if (res == -1) {
LOGE("cal_log_filepath failed, error (%s)\n",
strerror(errno));
continue;
}
get_log_by_type(des, log, files[i]);
free(des);
}
for (i = 0; i < count; i++)
free(files[i]);
free(files);
} else {
res = cal_log_filepath(&des, log, log->name, desdir);
if (res == -1) {
LOGE("cal_log_filepath failed, error (%s)\n",
strerror(errno));
return;
}
get_log_by_type(des, log, log->path);
free(des);
}
end = get_uptime();
spent = (int)((end - start) / 1000000000LL);
if (spent < 5)
LOGD("get (%s) spend %ds\n", log->name, spent);
else
LOGW("get (%s) spend %ds\n", log->name, spent);
}
#ifdef HAVE_TELEMETRICS_CLIENT
static void telemd_send_crash(struct event_t *e, char *eventid)
{
struct crash_t *crash;
char *class;
int ret;
crash = (struct crash_t *)e->private;
ret = asprintf(&class, "clearlinux/crash/%s", crash->name);
if (ret < 0) {
LOGE("compute string failed, out of memory\n");
return;
}
telemd_get_log(e->dir, eventid, CRASH_SEVERITY, class);
free(class);
}
static void telemd_send_info(struct event_t *e, char *eventid)
{
struct info_t *info;
char *class;
int ret;
info = (struct info_t *)e->private;
ret = asprintf(&class, "clearlinux/info/%s", info->name);
if (ret < 0) {
LOGE("compute string failed, out of memory\n");
return;
}
telemd_get_log(e->dir, eventid, INFO_SEVERITY, class);
free(class);
}
static void telemd_send_uptime(void)
{
struct sender_t *telemd = get_sender_by_name("telemd");
struct uptime_t *uptime;
char *class;
char boot_time[UPTIME_SIZE];
int hours;
int ret;
static int uptime_hours;
static int loop_uptime_event = 1;
if (!telemd)
return;
ret = get_uptime_string(boot_time, &hours);
if (ret < 0) {
LOGE("cannot get uptime - %s\n", strerror(-ret));
return;
}
uptime = telemd->uptime;
if (cfg_atoi(uptime->eventhours, uptime->eventhours_len,
&uptime_hours) == -1)
return;
if (hours / uptime_hours >= loop_uptime_event) {
char *content;
loop_uptime_event = (hours / uptime_hours) + 1;
ret = asprintf(&class, "clearlinux/uptime/%s", boot_time);
if (ret < 0) {
LOGE("compute string failed, out of memory\n");
return;
}
ret = asprintf(&content, "system boot time: %s", boot_time);
if (ret < 0) {
LOGE("compute string failed, out of memory\n");
free(class);
return;
}
telemd_send_data(content, NULL, INFO_SEVERITY, class);
free(class);
free(content);
}
}
static void telemd_send_reboot(char *eventid)
{
struct sender_t *telemd = get_sender_by_name("telemd");
char *class;
char reason[REBOOT_REASON_SIZE];
int ret;
if (!telemd)
return;
if (swupdated(telemd)) {
char *content;
ret = asprintf(&class, "clearlinux/swupdate/-");
if (ret < 0) {
LOGE("compute string failed, out of memory\n");
return;
}
ret = asprintf(&content, "system update to: %s",
gbuildversion);
if (ret < 0) {
LOGE("compute string failed, out of memory\n");
free(class);
return;
}
telemd_send_data(content, NULL, INFO_SEVERITY, class);
free(class);
free(content);
}
read_startupreason(reason, sizeof(reason));
ret = asprintf(&class, "clearlinux/reboot/%s", reason);
if (ret < 0) {
LOGE("compute string failed, out of memory\n");
return;
}
telemd_send_data("reboot", eventid, INFO_SEVERITY, class);
free(class);
}
static void telemd_send_vmevent(struct event_t *e, char *eventid, char *data,
size_t dlen)
{
char *vmkey;
char *event;
char *type;
char *rest;
size_t klen;
size_t elen;
size_t tlen;
size_t rlen;
char *vmlogpath = NULL;
char *class;
char *files[512];
int count;
int i;
uint32_t severity;
char *log;
int res;
struct vm_event_t *vme;
vmkey = strings_ind(data, dlen, 0, &klen);
event = strings_ind(data, dlen, 1, &elen);
type = strings_ind(data, dlen, 2, &tlen);
rest = strings_ind(data, dlen, 3, &rlen);
if (!vmkey || !event || !type || !rest)
return;
if (strcmp(event, "CRASH") == 0)
severity = CRASH_SEVERITY;
else
severity = INFO_SEVERITY;
/* if line contains log, fill vmlogpath */
log = strstr(rest, ANDROID_LOGS_DIR);
if (log) {
const char *logf;
if (!e->dir)
return;
logf = log + sizeof(ANDROID_LOGS_DIR) - 1;
if (asprintf(&vmlogpath, "%s/%s", e->dir, logf) == -1)
return;
}
vme = (struct vm_event_t *)e->private;
res = asprintf(&class, "%s/%s/%s", vme->vm->name, event, type);
if (res < 0) {
LOGE("compute string failed, out of memory\n");
goto free_vmlogpath;
}
if (!vmlogpath) {
telemd_send_data("vm event doesn't contain logs", eventid,
severity, class);
goto free_class;
}
/* send logs */
count = lsdir(vmlogpath, files, ARRAY_SIZE(files));
if (count > 2) {
for (i = 0; i < count; i++) {
if (!strstr(files[i], "/.") &&
!strstr(files[i], "/..")) {
telemd_send_data(files[i], eventid, severity,
class);
}
}
} else if (count < 0) {
LOGE("lsdir (%s) failed, error (%s)\n", vmlogpath,
strerror(-count));
} else {
LOGE("get (%d) files in (%s) ???\n", count, vmlogpath);
}
while (count > 0)
free(files[--count]);
free_class:
free(class);
free_vmlogpath:
if (vmlogpath)
free(vmlogpath);
return;
}
static int telemd_new_event(struct event_t *e, char *result, size_t rsize,
char **eid)
{
struct crash_t *crash;
struct info_t *info;
struct vm_event_t *vme;
char *key;
const char *e_subtype = NULL;
size_t e_subtype_len = 0;
const char *estr = etype_str[e->event_type];
size_t eslen = strlen(etype_str[e->event_type]);
switch (e->event_type) {
case CRASH:
crash = (struct crash_t *)e->private;
e_subtype = crash->name;
e_subtype_len = crash->name_len;
break;
case INFO:
info = (struct info_t *)e->private;
e_subtype = info->name;
e_subtype_len = info->name_len;
break;
case UPTIME:
return 0;
case REBOOT:
break;
case VM:
vme = (struct vm_event_t *)e->private;
estr = vme->vm->name;
eslen = vme->vm->name_len;
e_subtype = strings_ind(result, rsize, 2, &e_subtype_len);
if (!e_subtype)
return -1;
break;
default:
break;
}
key = generate_event_id(estr, eslen, e_subtype, e_subtype_len,
KEY_LONG);
if (!key) {
LOGE("failed to generate event id, %s\n", strerror(errno));
return -1;
}
*eid = key;
return 0;
}
static int telemd_event_analyze(struct event_t *e, char **result,
size_t *rsize)
{
if (e->event_type == VM) {
struct vm_event_t *vme = (struct vm_event_t *)e->private;
if (android_event_analyze(vme->vm_msg, vme->vm_msg_len,
result, rsize) == -1) {
LOGE("failed to analyze android event\n");
return -1;
}
}
return 0;
}
static void telemd_send(struct event_t *e)
{
size_t rsize;
char *result = NULL;
char *eid = NULL;
if (telemd_event_analyze(e, &result, &rsize) == -1) {
LOGE("failed to analyze event\n");
return;
}
if (telemd_new_event(e, result, rsize, &eid) == -1) {
LOGE("failed to request resouce\n");
if (result)
free(result);
return;
}
switch (e->event_type) {
case CRASH:
telemd_send_crash(e, eid);
break;
case INFO:
telemd_send_info(e, eid);
break;
case UPTIME:
telemd_send_uptime();
break;
case REBOOT:
telemd_send_reboot(eid);
break;
case VM:
telemd_send_vmevent(e, eid, result, rsize);
break;
default:
LOGE("unsupoorted event type %d\n", e->event_type);
}
if (eid)
free(eid);
if (result)
free(result);
}
#endif
static void crashlog_send_crash(struct event_t *e, char *eid,
char *data, size_t dlen)
{
char *data0;
char *data1;
char *data2;
size_t d0len;
size_t d1len;
size_t d2len;
struct crash_t *crash = (struct crash_t *)e->private;
int id;
struct log_t *log;
hist_raise_event(etype_str[e->event_type], crash->name, e->dir, "",
eid);
if (!e->dir)
return;
data0 = strings_ind(data, dlen, 0, &d0len);
data1 = strings_ind(data, dlen, 1, &d1len);
data2 = strings_ind(data, dlen, 2, &d2len);
if (!data1 || !data1 || !data2)
return;
generate_crashfile(e->dir, etype_str[e->event_type],
strlen(etype_str[e->event_type]), eid,
SHORT_KEY_LENGTH, crash->name, crash->name_len,
data0, d0len, data1, d1len, data2, d2len);
for_each_log_collect(id, log, crash) {
if (!log)
continue;
log->get(log, (void *)e->dir);
}
if (!strcmp(e->channel, "inotify")) {
/* get the trigger file */
char *src;
char *des;
if (asprintf(&des, "%s/%s", e->dir, e->path) == -1) {
LOGE("out of memory\n");
return;
}
if (asprintf(&src, "%s/%s", crash->trigger->path,
e->path) == -1) {
LOGE("out of memory\n");
free(des);
return;
}
if (do_copy_tail(src, des, 0) < 0)
LOGE("failed to copy (%s) to (%s)\n", src, des);
free(src);
free(des);
}
}
static void crashlog_send_info(struct event_t *e, char *eid)
{
int id;
struct info_t *info = (struct info_t *)e->private;
struct log_t *log;
hist_raise_event(etype_str[e->event_type], info->name, e->dir, "", eid);
if (!e->dir)
return;
for_each_log_collect(id, log, info) {
if (!log)
continue;
log->get(log, (void *)e->dir);
}
}
static void crashlog_send_uptime(void)
{
hist_raise_uptime(NULL);
}
static void crashlog_send_reboot(struct event_t *e, char *eid)
{
char reason[REBOOT_REASON_SIZE];
char *key;
struct sender_t *crashlog;
crashlog = get_sender_by_name("crashlog");
if (!crashlog)
return;
if (swupdated(crashlog)) {
key = generate_event_id("INFO", 4, "SWUPDATE", 8, KEY_SHORT);
if (key == NULL) {
LOGE("generate event id failed, error (%s)\n",
strerror(errno));
return;
}
hist_raise_event("INFO", "SWUPDATE", NULL, "", key);
free(key);
}
read_startupreason(reason, sizeof(reason));
hist_raise_event(etype_str[e->event_type], reason, NULL, "", eid);
}
static void crashlog_send_vmevent(struct event_t *e, char *eid,
char *data, size_t dlen)
{
char *vmkey;
char *event;
char *type;
char *rest;
size_t klen;
size_t elen;
size_t tlen;
size_t rlen;
char *vmlogpath;
char *log;
int res;
int cnt;
ext2_filsys datafs;
struct sender_t *crashlog = get_sender_by_name("crashlog");
struct vm_event_t *vme = (struct vm_event_t *)e->private;
enum vmrecord_mark_t mark = SUCCESS;
if (!crashlog)
return;
vmkey = strings_ind(data, dlen, 0, &klen);
event = strings_ind(data, dlen, 1, &elen);
type = strings_ind(data, dlen, 2, &tlen);
rest = strings_ind(data, dlen, 3, &rlen);
if (!vmkey || !event || !type || !rest)
return;
hist_raise_event(vme->vm->name, type, e->dir, "", eid);
if (!e->dir)
goto mark_record;
generate_crashfile(e->dir, event, elen, eid, SHORT_KEY_LENGTH, type,
tlen, vme->vm->name, vme->vm->name_len, vmkey, klen,
NULL, 0);
log = strstr(rest, ANDROID_LOGS_DIR);
if (!log)
goto mark_record;
/* if line contains log, we need dump each file in the logdir */
vmlogpath = log + 1;
if (e2fs_open(loop_dev, &datafs) == -1) {
mark = WAITING_SYNC;
goto mark_record;
}
res = e2fs_dump_dir_by_dpath(datafs, vmlogpath, e->dir, &cnt);
e2fs_close(datafs);
if (res == -1) {
if (cnt) {
LOGE("dump (%s) abort at (%d)\n", vmlogpath, cnt);
mark = WAITING_SYNC;
} else {
LOGW("(%s) doesn't exsit\n", vmlogpath);
mark = MISS_LOG;
}
}
if (cnt == 1) {
LOGW("%s is empty, will sync it in the next loop\n", vmlogpath);
mark = WAITING_SYNC;
}
if (res == -1 || cnt == -1) {
if (remove_r(e->dir) == -1)
LOGE("failed to remove %s, %s\n", e->dir,
strerror(errno));
free(e->dir);
e->dir = NULL;
}
mark_record:
vmrecord_open_mark(&crashlog->vmrecord, vmkey, klen, mark);
return;
}
static int crashlog_event_analyze(struct event_t *e, char **result,
size_t *rsize)
{
struct crash_t *rcrash;
struct crash_t *crash;
char *trfile = NULL;
struct vm_event_t *vme;
switch (e->event_type) {
case CRASH:
rcrash = (struct crash_t *)e->private;
if (!strcmp(rcrash->trigger->type, "dir")) {
if (asprintf(&trfile, "%s/%s", rcrash->trigger->path,
e->path) == -1) {
LOGE("failed to asprintf\n");
return -1;
}
}
crash = rcrash->reclassify(rcrash, trfile, result, rsize);
if (trfile)
free(trfile);
if (!crash) {
LOGE("failed to reclassify (%s)\n", rcrash->name);
return -1;
}
/* change the class */
e->private = (void *)crash;
break;
case VM:
vme = (struct vm_event_t *)e->private;
if (android_event_analyze(vme->vm_msg, vme->vm_msg_len,
result, rsize) == -1) {
LOGE("failed to analyze android event\n");
return -1;
}
break;
default:
break;
}
return 0;
}
static int crashlog_new_event(struct event_t *e, char *result, size_t rsize,
char **eid)
{
char *key;
const char *e_subtype = NULL;
size_t e_subtype_len = 0;
struct crash_t *crash;
struct info_t *info;
struct vm_event_t *vme;
enum e_dir_mode mode;
int need_logs = 0;
struct sender_t *crashlog;
char *vmkey;
size_t vklen;
const char *estr = etype_str[e->event_type];
size_t eslen = strlen(etype_str[e->event_type]);
switch (e->event_type) {
case CRASH:
crash = (struct crash_t *)e->private;
e_subtype = crash->name;
e_subtype_len = crash->name_len;
if (to_collect_logs(crash) || !strcmp(e->channel, "inotify")) {
need_logs = 1;
mode = MODE_CRASH;
}
break;
case INFO:
info = (struct info_t *)e->private;
e_subtype = info->name;
e_subtype_len = info->name_len;
if (to_collect_logs(info) || !strcmp(e->channel, "inotify")) {
need_logs = 1;
mode = MODE_STATS;
}
break;
case UPTIME:
return 0;
case REBOOT:
break;
case VM:
vme = (struct vm_event_t *)e->private;
estr = vme->vm->name;
eslen = vme->vm->name_len;
e_subtype = strings_ind(result, rsize, 2, &e_subtype_len);
if (!e_subtype)
return -1;
need_logs = 1;
mode = MODE_VMEVENT;
break;
default:
break;
}
key = generate_event_id(estr, eslen, e_subtype, e_subtype_len,
KEY_SHORT);
if (!key) {
LOGE("failed to generate event id, %s\n", strerror(errno));
goto fail;
}
if (!need_logs) {
*eid = key;
return 0;
}
if (crashlog_check_space() == -1) {
hist_raise_event(estr, e_subtype, "SPACE_FULL", "", key);
free(key);
goto fail;
}
e->dir = generate_log_dir(mode, key, &e->dlen);
if (!e->dir) {
LOGE("failed to generate crashlog dir\n");
free(key);
goto fail;
}
*eid = key;
return 0;
fail:
if (e->event_type == VM) {
crashlog = get_sender_by_name("crashlog");
vmkey = strings_ind(result, rsize, 0, &vklen);
if (!crashlog || !vmkey)
return -1;
vmrecord_open_mark(&crashlog->vmrecord, vmkey, vklen, NO_RESRC);
}
return -1;
}
static void crashlog_send(struct event_t *e)
{
int id;
struct log_t *log;
size_t rsize = 0;
char *result = NULL;
char *eid = NULL;
if (crashlog_event_analyze(e, &result, &rsize) == -1) {
LOGE("failed to analyze event\n");
return;
}
if (crashlog_new_event(e, result, rsize, &eid) == -1) {
LOGE("failed to request resouce\n");
if (result)
free(result);
return;
}
for_each_log(id, log, conf) {
if (!log)
continue;
log->get = crashlog_get_log;
}
switch (e->event_type) {
case CRASH:
crashlog_send_crash(e, eid, result, rsize);
break;
case INFO:
crashlog_send_info(e, eid);
break;
case UPTIME:
crashlog_send_uptime();
break;
case REBOOT:
crashlog_send_reboot(e, eid);
break;
case VM:
crashlog_send_vmevent(e, eid, result, rsize);
break;
default:
LOGE("unsupoorted event type %d\n", e->event_type);
}
if (e->dir)
log_grows(e->dir, e->dlen);
if (eid)
free(eid);
if (result)
free(result);
}
int init_sender(void)
{
int id;
int fd;
struct sender_t *sender;
struct uptime_t *uptime;
for_each_sender(id, sender, conf) {
if (!sender)
continue;
if (!directory_exists(sender->outdir))
if (mkdir_p(sender->outdir) < 0) {
LOGE("mkdir (%s) failed, error (%s)\n",
sender->outdir, strerror(errno));
return -1;
}
if (init_properties(sender)) {
LOGE("init sender failed\n");
return -1;
}
/* touch uptime file, to add inotify */
uptime = sender->uptime;
if (uptime) {
fd = open(uptime->path, O_RDWR | O_CREAT, 0666);
if (fd < 0) {
LOGE("failed to open (%s), error (%s)\n",
uptime->path, strerror(errno));
return -1;
}
close(fd);
}
if (!strcmp(sender->name, "crashlog")) {
sender->send = crashlog_send;
if (prepare_history())
return -1;
if (asprintf(&sender->vmrecord.path,
"%s/VM_eventsID.log",
sender->outdir) == -1) {
LOGE("failed to asprintf\n");
return -1;
}
pthread_mutex_init(&sender->vmrecord.mtx, NULL);
if (dir_blocks_size(sender->outdir, sender->outdir_len,
&sender->outdir_blocks_size)
== -1) {
LOGE("failed to init outdir size\n");
return -1;
}
#ifdef HAVE_TELEMETRICS_CLIENT
} else if (!strcmp(sender->name, "telemd")) {
sender->send = telemd_send;
#endif
}
}
return 0;
}