mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-05-28 18:04:23 +00:00
tools: acrn-crashlog: Defer the vm events processing when failed
In the original design, acrnprobe marked all handled VMs'events as "synced" in file vmrecordid(this patch changes the name to VM_eventsID.log). Currently, the Android log events are not logged if the first attempt at reading collecting them from the VM fails. This patch changes the logic so that the acrn-crashlog tool will retry continuously. This patch defines different tags for handled VMs'events, and only marks VMs'events "synced" after it returns successfully. Signed-off-by: Liu, Xinwu <xinwu.liu@intel.com> Reviewed-by: xiaojin2 <xiaojing.liu@intel.com> Reviewed-by: Jin Zhi <zhi.jin@intel.com> Acked-by: Geoffroy Van Cutsem <geoffroy.vancutsem@intel.com> Acked-by: Chen gang <gang.c.chen@intel.com>
This commit is contained in:
parent
ccc222d193
commit
41b39c5e1f
@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <openssl/sha.h>
|
||||
@ -20,25 +21,27 @@
|
||||
#define VM_WARNING_LINES 2000
|
||||
#define LOOP_DEV_MAX 8
|
||||
|
||||
static char *android_img = "/data/android/android.img";
|
||||
#define ANDROID_EVT_KEY_LEN 20
|
||||
|
||||
static const char *android_img = "/data/android/android.img";
|
||||
char *loop_dev;
|
||||
|
||||
/* Find the head of str, caller must guarantee that 'str' is not in
|
||||
* the first line.
|
||||
*/
|
||||
static char *line_head(char *str)
|
||||
static char *line_head(const char *str)
|
||||
{
|
||||
while (*str != '\n')
|
||||
str--;
|
||||
|
||||
return str + 1;
|
||||
return (char *)(str + 1);
|
||||
}
|
||||
|
||||
/* Find the next event that needs to be synced.
|
||||
* There is a history_event file in UOS side, it records UOS's events in
|
||||
* real-time. Generally, the cursor point to the first unsynchronized line.
|
||||
*/
|
||||
static char *vm_next_event_to_sync(char *cursor, struct vm_t *vm)
|
||||
static char *vm_next_event_to_sync(const char *cursor, const struct vm_t *vm)
|
||||
{
|
||||
char *line_to_sync = (char *)~(0);
|
||||
char *syncevent;
|
||||
@ -88,22 +91,29 @@ static char *vm_next_event_to_sync(char *cursor, struct vm_t *vm)
|
||||
|
||||
if (line_to_sync == (char *)~(0))
|
||||
return NULL;
|
||||
else
|
||||
return line_to_sync;
|
||||
|
||||
return line_to_sync;
|
||||
}
|
||||
|
||||
static int generate_log_vmrecord(char *path)
|
||||
#define VMRECORD_HEAD_LINES 6
|
||||
#define VMRECORD_TAG_LEN 9
|
||||
#define VMRECORD_TAG_WAITING_SYNC " <=="
|
||||
#define VMRECORD_TAG_NOT_FOUND "NOT_FOUND"
|
||||
#define VMRECORD_TAG_SUCCESS " "
|
||||
static int generate_log_vmrecord(const char *path)
|
||||
{
|
||||
char *head = "/* This file records vm id synced/will-sync from VMs,\n"
|
||||
" * the tag \"<==\" indicates the events waiting to sync.\n"
|
||||
" */\n\n";
|
||||
const char * const head =
|
||||
"/* DONT EDIT!\n"
|
||||
" * This file records VM id synced or about to be synched,\n"
|
||||
" * the tag \"<==\" indicates event waiting to sync.\n"
|
||||
" * the tag \"NOT_FOUND\" indicates event not found in UOS.\n"
|
||||
" */\n\n";
|
||||
|
||||
LOGD("generate log_vmrecordid in (%s)\n", path);
|
||||
LOGD("Generate (%s)\n", path);
|
||||
return overwrite_file(path, head);
|
||||
}
|
||||
|
||||
enum refresh_type_t {
|
||||
enum stage1_refresh_type_t {
|
||||
MM_ONLY,
|
||||
MM_FILE
|
||||
};
|
||||
@ -115,8 +125,10 @@ enum refresh_type_t {
|
||||
*
|
||||
* The design reason is to give UOS some time to log to storage.
|
||||
*/
|
||||
static int refresh_key_synced_stage1(struct sender_t *sender, struct vm_t *vm,
|
||||
char *key, enum refresh_type_t type)
|
||||
static int refresh_key_synced_stage1(const struct sender_t *sender,
|
||||
struct vm_t *vm,
|
||||
const char *key,
|
||||
enum stage1_refresh_type_t type)
|
||||
{
|
||||
char log_new[64];
|
||||
char *log_vmrecordid;
|
||||
@ -132,7 +144,7 @@ static int refresh_key_synced_stage1(struct sender_t *sender, struct vm_t *vm,
|
||||
/* the length of key must be 20, and its value can not be
|
||||
* 00000000000000000000.
|
||||
*/
|
||||
if ((strlen(key) == 20) &&
|
||||
if ((strlen(key) == ANDROID_EVT_KEY_LEN) &&
|
||||
strcmp(key, "00000000000000000000")) {
|
||||
sprintf(vm->last_synced_line_key[sid],
|
||||
"%s", key);
|
||||
@ -145,41 +157,57 @@ static int refresh_key_synced_stage1(struct sender_t *sender, struct vm_t *vm,
|
||||
if (!file_exists(log_vmrecordid))
|
||||
generate_log_vmrecord(log_vmrecordid);
|
||||
|
||||
sprintf(log_new, "%s %s <==\n", vm->name, key);
|
||||
sprintf(log_new, "%s %s %s\n", vm->name, key,
|
||||
VMRECORD_TAG_WAITING_SYNC);
|
||||
append_file(log_vmrecordid, log_new);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOGE("try to record a invalid key (%s) for (%s)\n",
|
||||
LOGE("try to record an invalid key (%s) for (%s)\n",
|
||||
key, vm->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int refresh_key_synced_stage2(struct mm_file_t *m_vm_records, char *key)
|
||||
enum stage2_refresh_type_t {
|
||||
SUCCESS,
|
||||
NOT_FOUND
|
||||
};
|
||||
|
||||
static int refresh_key_synced_stage2(const struct mm_file_t *m_vm_records,
|
||||
const char *key,
|
||||
enum stage2_refresh_type_t type)
|
||||
{
|
||||
char *begin, *end;
|
||||
char *p;
|
||||
char *lhead, *ltail;
|
||||
char *tag;
|
||||
|
||||
if (*key) {
|
||||
begin = strstr(m_vm_records->begin, " <==");
|
||||
end = strrstr(m_vm_records->begin, key);
|
||||
if (!begin || !end)
|
||||
return -1;
|
||||
if (!key || strlen(key) != ANDROID_EVT_KEY_LEN || !m_vm_records ||
|
||||
m_vm_records->size <= 0)
|
||||
return -1;
|
||||
|
||||
end = strchr(end, '\n');
|
||||
lhead = strstr(m_vm_records->begin, key);
|
||||
if (!lhead)
|
||||
return -1;
|
||||
|
||||
for (p = begin; p < end; p++) {
|
||||
if (*p == '<' || *p == '=')
|
||||
*p = ' ';
|
||||
}
|
||||
ltail = strchr(lhead, '\n');
|
||||
if (!ltail)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
tag = strstr(lhead, VMRECORD_TAG_WAITING_SYNC);
|
||||
if (!tag || tag >= ltail)
|
||||
return -1;
|
||||
|
||||
return -1;
|
||||
/* re-mark symbol "<==" for synced key */
|
||||
if (type == SUCCESS)
|
||||
memcpy(tag, VMRECORD_TAG_SUCCESS, VMRECORD_TAG_LEN);
|
||||
else if (type == NOT_FOUND)
|
||||
memcpy(tag, VMRECORD_TAG_NOT_FOUND, VMRECORD_TAG_LEN);
|
||||
else
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_vm_history(struct vm_t *vm, struct sender_t *sender,
|
||||
static int get_vm_history(struct vm_t *vm, const struct sender_t *sender,
|
||||
void **data)
|
||||
{
|
||||
char vm_history[PATH_MAX];
|
||||
@ -206,6 +234,7 @@ static int get_vm_history(struct vm_t *vm, struct sender_t *sender,
|
||||
if (ret) {
|
||||
LOGE("read (%s) with error (%s)\n", vm_history,
|
||||
strerror(errno));
|
||||
*data = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -220,15 +249,16 @@ static int get_vm_history(struct vm_t *vm, struct sender_t *sender,
|
||||
return size;
|
||||
}
|
||||
|
||||
static void sync_lines_stage1(struct sender_t *sender, void *data[])
|
||||
static void sync_lines_stage1(const struct sender_t *sender, const void *data[])
|
||||
{
|
||||
int id, sid;
|
||||
int ret;
|
||||
struct vm_t *vm;
|
||||
char *start;
|
||||
char *line_to_sync;
|
||||
char vmkey[SHA_DIGEST_LENGTH + 1] = {0};
|
||||
char *vm_format = "%*[^ ]%*[ ]%[^ ]%*c";
|
||||
char vmkey[ANDROID_WORD_LEN];
|
||||
const char * const vm_format =
|
||||
IGN_ONEWORD ANDROID_KEY_FMT IGN_RESTS;
|
||||
|
||||
sid = sender_id(sender);
|
||||
if (sid == -1)
|
||||
@ -265,7 +295,7 @@ static void sync_lines_stage1(struct sender_t *sender, void *data[])
|
||||
vmkey[0] = 0;
|
||||
ret = sscanf(line_to_sync, vm_format, vmkey);
|
||||
if (ret != 1) {
|
||||
LOGE("get a invalid line from (%s), skip\n",
|
||||
LOGE("get an invalid line from (%s), skip\n",
|
||||
vm->name);
|
||||
start = next_line(line_to_sync);
|
||||
continue;
|
||||
@ -281,15 +311,16 @@ static void sync_lines_stage1(struct sender_t *sender, void *data[])
|
||||
|
||||
}
|
||||
|
||||
static void sync_lines_stage2(struct sender_t *sender, void *data[],
|
||||
void (*fn)(char*, struct vm_t *))
|
||||
static void sync_lines_stage2(const struct sender_t *sender, const void *data[],
|
||||
int (*fn)(const char*, const struct vm_t *))
|
||||
{
|
||||
struct mm_file_t *m_vm_records;
|
||||
char *line;
|
||||
char *cursor;
|
||||
char *record_fmt = "%[^ ]%*[ ]%[^ ]%*c";
|
||||
char vm_name[64];
|
||||
char vmkey[SHA_DIGEST_LENGTH + 1] = {0};
|
||||
const char * const record_fmt =
|
||||
VM_NAME_FMT ANDROID_KEY_FMT IGN_RESTS;
|
||||
char vm_name[32];
|
||||
char vmkey[ANDROID_WORD_LEN];
|
||||
int id;
|
||||
struct vm_t *vm;
|
||||
int ret;
|
||||
@ -300,18 +331,21 @@ static void sync_lines_stage2(struct sender_t *sender, void *data[],
|
||||
strerror(errno));
|
||||
return;
|
||||
}
|
||||
if (!m_vm_records->size) {
|
||||
LOGE("size(0b) of (%s)\n", sender->log_vmrecordid);
|
||||
return;
|
||||
if (!m_vm_records->size ||
|
||||
mm_count_lines(m_vm_records) < VMRECORD_HEAD_LINES) {
|
||||
LOGE("(%s) invalid\n", sender->log_vmrecordid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
cursor = strstr(m_vm_records->begin, " <==");
|
||||
cursor = strstr(m_vm_records->begin, " " VMRECORD_TAG_WAITING_SYNC);
|
||||
if (!cursor)
|
||||
goto out;
|
||||
|
||||
line = line_head(cursor);
|
||||
while (line) {
|
||||
char *vm_hist_line;
|
||||
|
||||
vmkey[0] = 0;
|
||||
/* VMNAME xxxxxxxxxxxxxxxxxxxx <== */
|
||||
ret = sscanf(line, record_fmt, vm_name, vmkey);
|
||||
if (ret != 2) {
|
||||
@ -331,31 +365,43 @@ static void sync_lines_stage2(struct sender_t *sender, void *data[],
|
||||
|
||||
vm_hist_line = strstr(data[id], vmkey);
|
||||
if (!vm_hist_line) {
|
||||
LOGE("not find (%s) in (%s),", vmkey, vm->name);
|
||||
LOGE("history_event in UOS was deleted?\n");
|
||||
LOGE("mark vmevent(%s) as unfound,", vmkey);
|
||||
LOGE("history_event in UOS was recreated?\n");
|
||||
refresh_key_synced_stage2(m_vm_records, vmkey,
|
||||
NOT_FOUND);
|
||||
break;
|
||||
}
|
||||
|
||||
fn(line_head(vm_hist_line), vm);
|
||||
ret = fn(line_head(vm_hist_line), vm);
|
||||
if (!ret)
|
||||
refresh_key_synced_stage2(m_vm_records, vmkey,
|
||||
SUCCESS);
|
||||
}
|
||||
|
||||
line = next_line(line);
|
||||
cursor = next_line(line);
|
||||
if (!cursor)
|
||||
break;
|
||||
|
||||
line = strstr(cursor, VMRECORD_TAG_WAITING_SYNC);
|
||||
if (!line)
|
||||
break;
|
||||
|
||||
line = line_head(line);
|
||||
}
|
||||
|
||||
out:
|
||||
refresh_key_synced_stage2(m_vm_records, vmkey);
|
||||
unmap_file(m_vm_records);
|
||||
}
|
||||
|
||||
/* This function only for initialization */
|
||||
static void get_last_line_synced(struct sender_t *sender)
|
||||
static void get_last_line_synced(const struct sender_t *sender)
|
||||
{
|
||||
int id;
|
||||
int sid;
|
||||
int ret;
|
||||
struct vm_t *vm;
|
||||
char vmkey[SHA_DIGEST_LENGTH + 10] = {0};
|
||||
char word[256];
|
||||
char vmkey[ANDROID_WORD_LEN];
|
||||
char vm_name[32];
|
||||
|
||||
if (!sender)
|
||||
return;
|
||||
@ -375,11 +421,11 @@ static void get_last_line_synced(struct sender_t *sender)
|
||||
if (vm->last_synced_line_key[sid][0])
|
||||
continue;
|
||||
|
||||
snprintf(word, sizeof(word), "%s ", vm->name);
|
||||
ret = file_read_key_value_r(sender->log_vmrecordid,
|
||||
word, vmkey);
|
||||
snprintf(vm_name, sizeof(vm_name), "%s ", vm->name);
|
||||
ret = file_read_key_value_r(sender->log_vmrecordid, vm_name,
|
||||
sizeof(vmkey), vmkey);
|
||||
if (ret == -ENOENT) {
|
||||
LOGD("no log_vmrecordid under (%s), will generete\n",
|
||||
LOGD("no (%s), will generate\n",
|
||||
sender->log_vmrecordid);
|
||||
generate_log_vmrecord(sender->log_vmrecordid);
|
||||
continue;
|
||||
@ -393,7 +439,6 @@ static void get_last_line_synced(struct sender_t *sender)
|
||||
continue;
|
||||
}
|
||||
|
||||
vmkey[SHA_DIGEST_LENGTH] = 0;
|
||||
ret = refresh_key_synced_stage1(sender, vm, vmkey, MM_ONLY);
|
||||
if (ret < 0) {
|
||||
LOGE("get a non-key vm event (%s) for (%s)\n",
|
||||
@ -478,30 +523,30 @@ static char *setup_loop_dev(void)
|
||||
}
|
||||
|
||||
/* find data partition, sector unit = 512 bytes */
|
||||
char patition_start[32] = {0};
|
||||
char sectors[32] = {0};
|
||||
char partition_start[32];
|
||||
char sectors[32];
|
||||
unsigned long pstart;
|
||||
char *partition;
|
||||
char *partition_fmt = "%*[^ ]%*[ ]%[^ ]%*[ ]%*[^ ]%*[ ]%[^ ]%*c";
|
||||
const char * const partition_fmt =
|
||||
IGN_ONEWORD "%31[^ ]" IGN_SPACES
|
||||
IGN_ONEWORD "%31[^ ]" IGN_RESTS;
|
||||
char *cursor = out;
|
||||
int ret;
|
||||
|
||||
while (cursor &&
|
||||
(partition = strstr(cursor, android_img))) {
|
||||
cursor = strchr(partition, '\n');
|
||||
memset(patition_start, 0, sizeof(patition_start));
|
||||
memset(sectors, 0, sizeof(sectors));
|
||||
|
||||
ret = sscanf(partition, partition_fmt, patition_start, sectors);
|
||||
ret = sscanf(partition, partition_fmt,
|
||||
partition_start, sectors);
|
||||
if (ret != 2)
|
||||
continue;
|
||||
|
||||
LOGD("start (%s) sectors(%s)\n", patition_start, sectors);
|
||||
LOGD("start (%s) sectors(%s)\n", partition_start, sectors);
|
||||
/* size < 1G */
|
||||
if (atoi(sectors) < 1 * 2 * 1024 * 1024)
|
||||
continue;
|
||||
|
||||
pstart = atol(patition_start) * 512;
|
||||
pstart = atol(partition_start) * 512;
|
||||
if (pstart == 0)
|
||||
continue;
|
||||
|
||||
@ -522,6 +567,7 @@ static char *setup_loop_dev(void)
|
||||
if (ret != 0)
|
||||
LOGE("(losetup -d %s) failed, return %d\n",
|
||||
loop_dev, ret);
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -539,12 +585,13 @@ success:
|
||||
static int ping_vm_fs(char *loop_dev)
|
||||
{
|
||||
int id;
|
||||
int res;
|
||||
int count = 0;
|
||||
struct vm_t *vm;
|
||||
struct mm_file_t *vm_hist;
|
||||
char vm_history[PATH_MAX];
|
||||
char cmd[512];
|
||||
char prefix[] = "#V1.0 CURRENTUPTIME";
|
||||
const char prefix[] = "#V1.0 CURRENTUPTIME";
|
||||
|
||||
/* ensure history_event in uos available */
|
||||
for_each_vm(id, vm, conf) {
|
||||
@ -556,7 +603,15 @@ static int ping_vm_fs(char *loop_dev)
|
||||
snprintf(cmd, sizeof(cmd),
|
||||
"dump logs/history_event %s", vm_history);
|
||||
|
||||
debugfs_cmd(loop_dev, cmd, NULL);
|
||||
res = remove(vm_history);
|
||||
if (res == -1 && errno != ENOENT)
|
||||
LOGE("remove %s failed\n", vm_history);
|
||||
|
||||
res = debugfs_cmd(loop_dev, cmd, NULL);
|
||||
if (res) {
|
||||
vm->online = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
vm_hist = mmap_file(vm_history);
|
||||
if (vm_hist == NULL) {
|
||||
@ -579,8 +634,14 @@ static int ping_vm_fs(char *loop_dev)
|
||||
return count;
|
||||
}
|
||||
|
||||
void refresh_vm_history(struct sender_t *sender,
|
||||
void (*fn)(char*, struct vm_t *))
|
||||
/* This function searches all android vms' new events and call the fn for
|
||||
* each event.
|
||||
*
|
||||
* Note that: fn should return 0 to indicate event has been handled,
|
||||
* or fn will be called in a time loop until it returns 0.
|
||||
*/
|
||||
void refresh_vm_history(const struct sender_t *sender,
|
||||
int (*fn)(const char*, const struct vm_t *))
|
||||
{
|
||||
int ret;
|
||||
int id;
|
||||
@ -612,6 +673,6 @@ void refresh_vm_history(struct sender_t *sender,
|
||||
get_vm_history(vm, sender, &data[id]);
|
||||
}
|
||||
|
||||
sync_lines_stage2(sender, data, fn);
|
||||
sync_lines_stage1(sender, data);
|
||||
sync_lines_stage2(sender, (const void **)data, fn);
|
||||
sync_lines_stage1(sender, (const void **)data);
|
||||
}
|
||||
|
@ -9,7 +9,33 @@
|
||||
|
||||
extern char *loop_dev;
|
||||
|
||||
void refresh_vm_history(struct sender_t *sender,
|
||||
void (*fn)(char*, struct vm_t *));
|
||||
#define VMEVT_HANDLED 0
|
||||
#define VMEVT_DEFER -1
|
||||
|
||||
#define IGN_SPACES "%*[ ]"
|
||||
#define IGN_RESTS "%*c"
|
||||
#define IGN_ONEWORD "%*[^ ]" IGN_SPACES
|
||||
#define VM_NAME_FMT "%8[A-Z0-9]" IGN_SPACES
|
||||
|
||||
/* These below macros were defined to obtain strings from
|
||||
* andorid history_event
|
||||
*/
|
||||
#define ANDROID_WORD_LEN 32
|
||||
|
||||
/* Strings are constructed by A-Z, len < 8, e.g., CRASH REBOOT */
|
||||
#define ANDROID_ENEVT_FMT "%8[A-Z]" IGN_SPACES
|
||||
/* Hashkeys are constructed by 0-9&a-z, len = 20, e.g., 0b34ae1afba54aee5cd0.
|
||||
* But the hashkey was printed to history_event file in andorid side by using
|
||||
* format "%22s", so also using %22 here.
|
||||
*/
|
||||
#define ANDROID_KEY_FMT "%22[0-9a-z]" IGN_SPACES
|
||||
/* Strings, e.g., 2017-11-11/03:12:59 */
|
||||
#define ANDROID_LONGTIME_FMT "%20[0-9:/-]" IGN_SPACES
|
||||
/* It's a time or a subtype of event, e.g., JAVACRASH POWER-ON 424874:19:56 */
|
||||
#define ANDROID_TYPE_FMT "%16[A-Z0-9_:-]" IGN_SPACES
|
||||
#define ANDROID_LINE_REST_FMT "%4096[^\n]" IGN_RESTS
|
||||
|
||||
void refresh_vm_history(const struct sender_t *sender,
|
||||
int (*fn)(const char*, const struct vm_t *));
|
||||
|
||||
#endif
|
||||
|
@ -203,7 +203,7 @@ struct conf_t conf;
|
||||
int load_conf(const 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);
|
||||
int sender_id(const 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);
|
||||
|
@ -260,7 +260,7 @@ enum event_type_t get_conf_by_wd(int wd, void **private)
|
||||
|
||||
}
|
||||
|
||||
int sender_id(struct sender_t *s)
|
||||
int sender_id(const struct sender_t *s)
|
||||
{
|
||||
int id;
|
||||
struct sender_t *sender;
|
||||
|
@ -65,15 +65,18 @@ int main(int argc, char *argv[])
|
||||
int op;
|
||||
struct sender_t *sender;
|
||||
char cfg[PATH_MAX];
|
||||
char *config_path[2] = {CONFIG_CUSTOMIZE,
|
||||
CONFIG_INSTALL};
|
||||
struct option opts[] = {
|
||||
const char * const config_path[2] = {
|
||||
CONFIG_CUSTOMIZE,
|
||||
CONFIG_INSTALL
|
||||
};
|
||||
const struct option opts[] = {
|
||||
{ "config", required_argument, NULL, 'c' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
cfg[0] = 0;
|
||||
while ((op = getopt_long(argc, argv, "c:hV", opts,
|
||||
NULL)) != -1) {
|
||||
switch (op) {
|
||||
|
@ -70,7 +70,8 @@ static int get_buildversion(struct sender_t *sender)
|
||||
char *logbuildid;
|
||||
char *currentbuild = gbuildversion;
|
||||
|
||||
ret = file_read_key_value(OS_VERSION, OS_VERSION_KEY, gbuildversion);
|
||||
ret = file_read_key_value(OS_VERSION, OS_VERSION_KEY,
|
||||
sizeof(gbuildversion), gbuildversion);
|
||||
if (ret <= 0) {
|
||||
LOGE("failed to get version from %s, error (%s)\n",
|
||||
OS_VERSION, strerror(-ret));
|
||||
|
@ -276,7 +276,7 @@ static void get_log_cmd(struct log_t *log, char *desdir)
|
||||
}
|
||||
|
||||
#ifdef HAVE_TELEMETRICS_CLIENT
|
||||
static bool telemd_send_data(char *payload, char *eventid, uint32_t severity,
|
||||
static int telemd_send_data(char *payload, char *eventid, uint32_t severity,
|
||||
char *class)
|
||||
{
|
||||
int res;
|
||||
@ -312,12 +312,12 @@ static bool telemd_send_data(char *payload, char *eventid, uint32_t severity,
|
||||
}
|
||||
|
||||
tm_free_record(handle);
|
||||
return true;
|
||||
return 0;
|
||||
|
||||
free:
|
||||
tm_free_record(handle);
|
||||
fail:
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void telemd_get_log(struct log_t *log, void *data)
|
||||
@ -638,14 +638,15 @@ static void telemd_send_reboot(void)
|
||||
free(class);
|
||||
}
|
||||
|
||||
static void telemd_new_vmevent(char *line_to_sync, struct vm_t *vm)
|
||||
static int telemd_new_vmevent(const char *line_to_sync,
|
||||
const struct vm_t *vm)
|
||||
{
|
||||
char event[96] = {0};
|
||||
char longtime[96] = {0};
|
||||
char type[96] = {0};
|
||||
char rest[PATH_MAX] = {0};
|
||||
char *vmlogpath[1] = {0};
|
||||
char vmkey[SHA_DIGEST_LENGTH + 1] = {0};
|
||||
char event[ANDROID_WORD_LEN];
|
||||
char longtime[ANDROID_WORD_LEN];
|
||||
char type[ANDROID_WORD_LEN];
|
||||
char rest[PATH_MAX];
|
||||
char *vmlogpath = NULL;
|
||||
char vmkey[ANDROID_WORD_LEN];
|
||||
char *log;
|
||||
char *class;
|
||||
char *eventid;
|
||||
@ -653,7 +654,8 @@ static void telemd_new_vmevent(char *line_to_sync, struct vm_t *vm)
|
||||
int count;
|
||||
int i;
|
||||
uint32_t severity;
|
||||
int ret;
|
||||
int res;
|
||||
int ret = VMEVT_HANDLED;
|
||||
|
||||
/* VM events in history_event look like this:
|
||||
*
|
||||
@ -662,13 +664,15 @@ static void telemd_new_vmevent(char *line_to_sync, struct vm_t *vm)
|
||||
* "REBOOT xxxxxxxxxxxxxxxxxxxx 2011-11-11/11:20:51 POWER-ON
|
||||
* 0000:00:00"
|
||||
*/
|
||||
char *vm_format = "%[^ ]%*[ ]%[^ ]%*[ ]%[^ ]%*[ ]%[^ ]%*[ ]%[^\n]%*c";
|
||||
const char * const vm_format =
|
||||
ANDROID_ENEVT_FMT ANDROID_KEY_FMT ANDROID_LONGTIME_FMT
|
||||
ANDROID_TYPE_FMT ANDROID_LINE_REST_FMT;
|
||||
|
||||
ret = sscanf(line_to_sync, vm_format, event, vmkey, longtime,
|
||||
res = sscanf(line_to_sync, vm_format, event, vmkey, longtime,
|
||||
type, rest);
|
||||
if (ret != 5) {
|
||||
LOGE("get a invalied line from (%s), skip\n", vm->name);
|
||||
return;
|
||||
if (res != 5) {
|
||||
LOGE("get an invalid line from (%s), skip\n", vm->name);
|
||||
return VMEVT_HANDLED;
|
||||
}
|
||||
|
||||
if (strcmp(event, "CRASH") == 0)
|
||||
@ -679,60 +683,77 @@ static void telemd_new_vmevent(char *line_to_sync, struct vm_t *vm)
|
||||
/* if line contains log, fill vmlogpath */
|
||||
log = strstr(rest, "/logs/");
|
||||
if (log) {
|
||||
struct sender_t *crashlog = get_sender_by_name("crashlog");
|
||||
struct sender_t *crashlog;
|
||||
|
||||
ret = find_file(crashlog->outdir, log + strlen("/logs/"),
|
||||
2, vmlogpath, 1);
|
||||
if (ret < 0) {
|
||||
crashlog = get_sender_by_name("crashlog");
|
||||
if (!crashlog)
|
||||
return VMEVT_HANDLED;
|
||||
|
||||
res = find_file(crashlog->outdir, log + strlen("/logs/"),
|
||||
2, &vmlogpath, 1);
|
||||
if (res < 0) {
|
||||
LOGE("find (%s) in (%s) failed, strerror (%s)\n",
|
||||
log + strlen("/logs/"), crashlog->outdir,
|
||||
strerror(-ret));
|
||||
return;
|
||||
strerror(-res));
|
||||
return VMEVT_DEFER;
|
||||
}
|
||||
}
|
||||
|
||||
ret = asprintf(&class, "%s/%s/%s", vm->name, event, type);
|
||||
if (ret < 0) {
|
||||
res = asprintf(&class, "%s/%s/%s", vm->name, event, type);
|
||||
if (res < 0) {
|
||||
LOGE("compute string failed, out of memory\n");
|
||||
ret = VMEVT_DEFER;
|
||||
goto free_vmlogpath;
|
||||
}
|
||||
|
||||
eventid = generate_eventid256(class);
|
||||
if (eventid == NULL) {
|
||||
LOGE("generate eventid failed, error (%s)\n", strerror(errno));
|
||||
ret = VMEVT_DEFER;
|
||||
goto free_class;
|
||||
}
|
||||
|
||||
if (vmlogpath[0] == 0) {
|
||||
telemd_send_data("no logs", eventid, severity, class);
|
||||
if (!vmlogpath) {
|
||||
res = telemd_send_data("no logs", eventid, severity, class);
|
||||
if (res == -1)
|
||||
ret = VMEVT_DEFER;
|
||||
|
||||
goto free;
|
||||
}
|
||||
|
||||
/* send logs */
|
||||
count = lsdir(vmlogpath[0], files, ARRAY_SIZE(files));
|
||||
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);
|
||||
!strstr(files[i], "/..")) {
|
||||
res = telemd_send_data(files[i], eventid,
|
||||
severity, class);
|
||||
if (res == -1)
|
||||
ret = VMEVT_DEFER;
|
||||
}
|
||||
}
|
||||
} else if (count == 2) {
|
||||
char *content;
|
||||
|
||||
ret = asprintf(&content, "no logs under (%s)", vmlogpath[0]);
|
||||
if (ret < 0) {
|
||||
res = asprintf(&content, "no logs under (%s)", vmlogpath);
|
||||
if (res > 0) {
|
||||
res = telemd_send_data(content, eventid, severity,
|
||||
class);
|
||||
if (res == -1)
|
||||
ret = VMEVT_DEFER;
|
||||
free(content);
|
||||
} else {
|
||||
LOGE("compute string failed, out of memory\n");
|
||||
goto free;
|
||||
ret = VMEVT_DEFER;
|
||||
}
|
||||
|
||||
telemd_send_data(content, eventid, severity, class);
|
||||
free(content);
|
||||
} else if (count < 0) {
|
||||
LOGE("lsdir (%s) failed, error (%s)\n", vmlogpath[0],
|
||||
LOGE("lsdir (%s) failed, error (%s)\n", vmlogpath,
|
||||
strerror(-count));
|
||||
ret = VMEVT_DEFER;
|
||||
} else {
|
||||
LOGE("get (%d) files in (%s) ???\n", count, vmlogpath[0]);
|
||||
LOGE("get (%d) files in (%s) ???\n", count, vmlogpath);
|
||||
ret = VMEVT_DEFER;
|
||||
}
|
||||
|
||||
while (count > 0)
|
||||
@ -743,8 +764,10 @@ free:
|
||||
free_class:
|
||||
free(class);
|
||||
free_vmlogpath:
|
||||
if (vmlogpath[0])
|
||||
free(vmlogpath[0]);
|
||||
if (vmlogpath)
|
||||
free(vmlogpath);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void telemd_send(struct event_t *e)
|
||||
@ -961,19 +984,21 @@ static void crashlog_send_reboot(void)
|
||||
free(key);
|
||||
}
|
||||
|
||||
static void crashlog_new_vmevent(char *line_to_sync, struct vm_t *vm)
|
||||
static int crashlog_new_vmevent(const char *line_to_sync,
|
||||
const struct vm_t *vm)
|
||||
{
|
||||
struct sender_t *crashlog;
|
||||
char event[96] = {0};
|
||||
char longtime[96] = {0};
|
||||
char type[96] = {0};
|
||||
char rest[PATH_MAX] = {0};
|
||||
char vmkey[SHA_DIGEST_LENGTH + 1] = {0};
|
||||
char event[ANDROID_WORD_LEN];
|
||||
char longtime[ANDROID_WORD_LEN];
|
||||
char type[ANDROID_WORD_LEN];
|
||||
char rest[PATH_MAX];
|
||||
char vmkey[ANDROID_WORD_LEN];
|
||||
char *vmlogpath = NULL;
|
||||
char *key;
|
||||
char *log;
|
||||
char *cmd;
|
||||
int ret;
|
||||
int ret = VMEVT_HANDLED;
|
||||
int res;
|
||||
int quota;
|
||||
char *dir;
|
||||
|
||||
@ -984,35 +1009,38 @@ static void crashlog_new_vmevent(char *line_to_sync, struct vm_t *vm)
|
||||
* "REBOOT xxxxxxxxxxxxxxxxxxxx 2011-11-11/11:20:51 POWER-ON
|
||||
* 0000:00:00"
|
||||
*/
|
||||
char *vm_format = "%[^ ]%*[ ]%[^ ]%*[ ]%[^ ]%*[ ]%[^ ]%*[ ]%[^\n]%*c";
|
||||
const char * const vm_format =
|
||||
ANDROID_ENEVT_FMT ANDROID_KEY_FMT ANDROID_LONGTIME_FMT
|
||||
ANDROID_TYPE_FMT ANDROID_LINE_REST_FMT;
|
||||
|
||||
ret = sscanf(line_to_sync, vm_format, event, vmkey, longtime,
|
||||
res = sscanf(line_to_sync, vm_format, event, vmkey, longtime,
|
||||
type, rest);
|
||||
if (ret != 5) {
|
||||
LOGE("get a invalied line from (%s), skip\n", vm->name);
|
||||
return;
|
||||
if (res != 5) {
|
||||
LOGE("get an invalid line from (%s), skip\n", vm->name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
crashlog = get_sender_by_name("crashlog");
|
||||
if (!crashlog)
|
||||
return;
|
||||
return ret;
|
||||
|
||||
quota = atoi(crashlog->spacequota);
|
||||
if (!space_available(crashlog->outdir, quota)) {
|
||||
hist_raise_infoerror("SPACE_FULL");
|
||||
return;
|
||||
return ret;
|
||||
}
|
||||
|
||||
key = generate_event_id("SOS", vmkey);
|
||||
if (key == NULL) {
|
||||
LOGE("generate event id failed, error (%s)\n",
|
||||
strerror(errno));
|
||||
return;
|
||||
return VMEVT_DEFER;
|
||||
}
|
||||
|
||||
dir = generate_log_dir(MODE_VMEVENT, key);
|
||||
if (dir == NULL) {
|
||||
LOGE("generate crashlog dir failed\n");
|
||||
ret = VMEVT_DEFER;
|
||||
goto free_key;
|
||||
}
|
||||
|
||||
@ -1020,20 +1048,32 @@ static void crashlog_new_vmevent(char *line_to_sync, struct vm_t *vm)
|
||||
*/
|
||||
log = strstr(rest, "/logs/");
|
||||
if (log) {
|
||||
ret = asprintf(&vmlogpath, "%s", log + 1);
|
||||
if (ret < 0) {
|
||||
res = asprintf(&vmlogpath, "%s", log + 1);
|
||||
if (res < 0) {
|
||||
LOGE("compute string failed, out of memory\n");
|
||||
remove(dir);
|
||||
ret = VMEVT_DEFER;
|
||||
goto free_dir;
|
||||
}
|
||||
|
||||
ret = asprintf(&cmd, "rdump %s %s", vmlogpath, dir);
|
||||
if (ret < 0) {
|
||||
res = asprintf(&cmd, "rdump %s %s", vmlogpath, dir);
|
||||
if (res < 0) {
|
||||
LOGE("compute string failed, out of memory\n");
|
||||
free(vmlogpath);
|
||||
remove(dir);
|
||||
ret = VMEVT_DEFER;
|
||||
goto free_dir;
|
||||
}
|
||||
|
||||
debugfs_cmd(loop_dev, cmd, NULL);
|
||||
res = debugfs_cmd(loop_dev, cmd, NULL);
|
||||
if (res) {
|
||||
LOGE("debugfs cmd %s failed (%d)\n", cmd, res);
|
||||
res = remove(dir);
|
||||
if (res == -1 && errno != ENOENT)
|
||||
LOGE("remove %s faield (%d)\n", dir, -errno);
|
||||
ret = VMEVT_DEFER;
|
||||
goto free_dir;
|
||||
}
|
||||
|
||||
free(cmd);
|
||||
free(vmlogpath);
|
||||
@ -1047,6 +1087,8 @@ free_dir:
|
||||
free(dir);
|
||||
free_key:
|
||||
free(key);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void crashlog_send(struct event_t *e)
|
||||
@ -1095,7 +1137,7 @@ int init_sender(void)
|
||||
if (!sender)
|
||||
continue;
|
||||
|
||||
ret = asprintf(&sender->log_vmrecordid, "%s/vmrecordid",
|
||||
ret = asprintf(&sender->log_vmrecordid, "%s/VM_eventsID.log",
|
||||
sender->outdir);
|
||||
if (ret < 0) {
|
||||
LOGE("compute string failed, out of memory\n");
|
||||
|
@ -94,6 +94,9 @@ int mm_count_lines(struct mm_file_t *mfile)
|
||||
if (!mfile || mfile->size < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (!mfile->size)
|
||||
return 0;
|
||||
|
||||
return strcnt(mfile->begin, '\n');
|
||||
}
|
||||
|
||||
@ -432,7 +435,7 @@ int replace_file_head(char *filename, char *text)
|
||||
*
|
||||
* @return 0 if successful, or a negative errno-style value if not.
|
||||
*/
|
||||
int overwrite_file(char *filename, char *value)
|
||||
int overwrite_file(const char *filename, const char *value)
|
||||
{
|
||||
FILE *fp;
|
||||
int ret = 0;
|
||||
@ -833,11 +836,13 @@ close:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int _file_read_key_value(char *path, char op, char *key, char *value)
|
||||
static int _file_read_key_value(const char *path, const char op,
|
||||
const char *key, const size_t limit,
|
||||
char *value)
|
||||
{
|
||||
int fd;
|
||||
int size;
|
||||
int len;
|
||||
size_t len;
|
||||
char *data;
|
||||
char *msg = NULL;
|
||||
char *end, *start;
|
||||
@ -855,6 +860,10 @@ static int _file_read_key_value(char *path, char op, char *key, char *value)
|
||||
size = get_file_size(path);
|
||||
if (size < 0)
|
||||
return size;
|
||||
if (!size) {
|
||||
errno = ENOMSG;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
fd = open(path, O_RDONLY);
|
||||
if (fd < 0)
|
||||
@ -872,12 +881,14 @@ static int _file_read_key_value(char *path, char op, char *key, char *value)
|
||||
errno = ENOMSG;
|
||||
goto unmap;
|
||||
}
|
||||
end = strchr(msg, '\n');
|
||||
|
||||
start = msg + strlen(key);
|
||||
end = strchr(start, '\n');
|
||||
if (end == NULL)
|
||||
end = data + size;
|
||||
|
||||
start = msg + strlen(key);
|
||||
len = end - start;
|
||||
len = MIN(len, limit - 1);
|
||||
memcpy(value, start, len);
|
||||
*(value + len) = 0;
|
||||
|
||||
@ -893,14 +904,16 @@ close:
|
||||
return -errno;
|
||||
}
|
||||
|
||||
int file_read_key_value(char *path, char *key, char *value)
|
||||
int file_read_key_value(const char *path, const char *key,
|
||||
const size_t limit, char *value)
|
||||
{
|
||||
return _file_read_key_value(path, 'l', key, value);
|
||||
return _file_read_key_value(path, 'l', key, limit, value);
|
||||
}
|
||||
|
||||
int file_read_key_value_r(char *path, char *key, char *value)
|
||||
int file_read_key_value_r(const char *path, const char *key,
|
||||
const size_t limit, char *value)
|
||||
{
|
||||
return _file_read_key_value(path, 'r', key, value);
|
||||
return _file_read_key_value(path, 'r', key, limit, value);
|
||||
}
|
||||
|
||||
int dir_contains(const char *dir, const char *filename, int exact,
|
||||
|
@ -81,7 +81,7 @@ int append_file(char *filename, char *text);
|
||||
int mm_replace_str_line(struct mm_file_t *mfile, char *replace,
|
||||
int line);
|
||||
int replace_file_head(char *filename, char *text);
|
||||
int overwrite_file(char *filename, char *value);
|
||||
int overwrite_file(const char *filename, const char *value);
|
||||
int readline(int fd, char buffer[MAXLINESIZE]);
|
||||
int file_read_string(const char *file, char *string, int size);
|
||||
void file_reset_init(const char *filename);
|
||||
@ -93,8 +93,10 @@ int space_available(char *path, int quota);
|
||||
int count_lines_in_file(const char *filename);
|
||||
int read_full_binary_file(const char *path, unsigned long *size,
|
||||
void **data);
|
||||
int file_read_key_value(char *path, char *key, char *value);
|
||||
int file_read_key_value_r(char *path, char *key, char *value);
|
||||
int file_read_key_value(const char *path, const char *key,
|
||||
const size_t limit, char *value);
|
||||
int file_read_key_value_r(const char *path, const char *key,
|
||||
const size_t limit, char *value);
|
||||
int dir_contains(const char *dir, const char *filename, int exact,
|
||||
char *fullname);
|
||||
int lsdir(const char *dir, char *fullname[], int limit);
|
||||
|
@ -9,7 +9,7 @@
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
|
||||
int strlinelen(char *str);
|
||||
char *strrstr(char *s, char *str);
|
||||
char *strrstr(const char *s, const char *str);
|
||||
char *next_line(char *buf);
|
||||
char *strtrim(char *str);
|
||||
int strcnt(char *str, char c);
|
||||
|
@ -37,16 +37,16 @@ int strlinelen(char *str)
|
||||
* @return a pointer to the beginning of the substring,
|
||||
* or NULL if the substring is not found.
|
||||
*/
|
||||
char *strrstr(char *s, char *substr)
|
||||
char *strrstr(const char *s, const char *substr)
|
||||
{
|
||||
char *found;
|
||||
char *p = s;
|
||||
const char *found;
|
||||
const char *p = s;
|
||||
|
||||
while ((found = strstr(p, substr)))
|
||||
p = found + 1;
|
||||
|
||||
if (p != s)
|
||||
return p - 1;
|
||||
return (char *)(p - 1);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user