mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2026-06-08 10:04:42 +00:00
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>
This commit is contained in:
443
misc/tools/acrn-crashlog/acrnprobe/probeutils.c
Normal file
443
misc/tools/acrn-crashlog/acrnprobe/probeutils.c
Normal file
@@ -0,0 +1,443 @@
|
||||
/*
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2018 Intel Corporation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <time.h>
|
||||
#include "property.h"
|
||||
#include "fsutils.h"
|
||||
#include "history.h"
|
||||
#include "load_conf.h"
|
||||
#include "log_sys.h"
|
||||
#include "probeutils.h"
|
||||
#include "strutils.h"
|
||||
|
||||
#define CRASH_CURRENT_LOG "currentcrashlog"
|
||||
#define STATS_CURRENT_LOG "currentstatslog"
|
||||
#define VM_CURRENT_LOG "currentvmlog"
|
||||
|
||||
#define BOOTID_NODE "/proc/sys/kernel/random/boot_id"
|
||||
#define BOOTID_LOG "currentbootid"
|
||||
|
||||
unsigned long long get_uptime(void)
|
||||
{
|
||||
long long time_ns;
|
||||
struct timespec ts;
|
||||
int res;
|
||||
|
||||
res = clock_gettime(CLOCK_BOOTTIME, &ts);
|
||||
if (res == -1)
|
||||
return res;
|
||||
|
||||
time_ns = (long long)ts.tv_sec * 1000000000LL +
|
||||
(long long)ts.tv_nsec;
|
||||
|
||||
return time_ns;
|
||||
}
|
||||
|
||||
int get_uptime_string(char *newuptime, int *hours)
|
||||
{
|
||||
long long tm;
|
||||
int seconds, minutes;
|
||||
int len;
|
||||
|
||||
tm = get_uptime();
|
||||
if (tm == -1)
|
||||
return -1;
|
||||
|
||||
/* seconds */
|
||||
*hours = (int)(tm / 1000000000LL);
|
||||
seconds = *hours % 60;
|
||||
|
||||
/* minutes */
|
||||
*hours /= 60;
|
||||
minutes = *hours % 60;
|
||||
|
||||
/* hours */
|
||||
*hours /= 60;
|
||||
|
||||
len = snprintf(newuptime, UPTIME_SIZE, "%04d:%02d:%02d", *hours,
|
||||
minutes, seconds);
|
||||
if (s_not_expect(len, UPTIME_SIZE))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_current_time_long(char *buf)
|
||||
{
|
||||
time_t t;
|
||||
struct tm *time_val;
|
||||
|
||||
time(&t);
|
||||
time_val = localtime((const time_t *)&t);
|
||||
if (!time_val)
|
||||
return -1;
|
||||
|
||||
return strftime(buf, LONG_TIME_SIZE, "%Y-%m-%d/%H:%M:%S ", time_val);
|
||||
}
|
||||
|
||||
static int compute_key(char *key, size_t klen, const char *seed,
|
||||
const size_t slen)
|
||||
{
|
||||
SHA256_CTX sha;
|
||||
char buf[VERSION_SIZE];
|
||||
int len;
|
||||
long long time_ns;
|
||||
char *tmp_key = key;
|
||||
unsigned char results[SHA256_DIGEST_LENGTH];
|
||||
size_t i;
|
||||
|
||||
if (!key || !seed || !slen)
|
||||
return -1;
|
||||
if (klen > SHA256_DIGEST_LENGTH * 2 || !klen)
|
||||
return -1;
|
||||
|
||||
SHA256_Init(&sha);
|
||||
time_ns = get_uptime();
|
||||
len = snprintf(buf, VERSION_SIZE, "%s%s%lld",
|
||||
gbuildversion, guuid, time_ns);
|
||||
if (s_not_expect(len , VERSION_SIZE))
|
||||
return -1;
|
||||
|
||||
SHA256_Update(&sha, (unsigned char *)buf, strnlen(buf, VERSION_SIZE));
|
||||
SHA256_Update(&sha, (unsigned char *)seed, strnlen(seed, slen));
|
||||
|
||||
SHA256_Final(results, &sha);
|
||||
|
||||
for (i = 0; i < klen / 2; i++) {
|
||||
len = snprintf(tmp_key, 3, "%02x", results[i]);
|
||||
if (s_not_expect(len, 3))
|
||||
return -1;
|
||||
tmp_key += 2;
|
||||
}
|
||||
*tmp_key = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an event id with specified type.
|
||||
*
|
||||
* @param seed1 Seed1.
|
||||
* @param seed2 Seed2, this parameter will be ignored if the value is NULL.
|
||||
* @param type The type of key. The length of generated id will be 20
|
||||
* characters if type is KEY_SHORT; 32 characters if type is
|
||||
* KEY_LONG.
|
||||
*
|
||||
* @return a pointer to result haskkey if successful, or NULL if not.
|
||||
*/
|
||||
char *generate_event_id(const char *seed1, size_t slen1, const char *seed2,
|
||||
size_t slen2, enum key_type type)
|
||||
{
|
||||
int ret;
|
||||
char *buf;
|
||||
char *key;
|
||||
size_t klen;
|
||||
|
||||
if (!seed1 || !slen1)
|
||||
return NULL;
|
||||
|
||||
if (type == KEY_SHORT)
|
||||
klen = SHORT_KEY_LENGTH;
|
||||
else if (type == KEY_LONG)
|
||||
klen = LONG_KEY_LENGTH;
|
||||
else
|
||||
return NULL;
|
||||
|
||||
key = (char *)malloc(klen + 1);
|
||||
if (!key) {
|
||||
LOGE("failed to generate event id, out of memory\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (seed2) {
|
||||
if (asprintf(&buf, "%s%s", seed1, seed2) == -1) {
|
||||
LOGE("failed to generate event id, out of memory\n");
|
||||
free(key);
|
||||
return NULL;
|
||||
}
|
||||
ret = compute_key(key, klen, (const char *)buf, slen1 + slen2);
|
||||
free(buf);
|
||||
} else {
|
||||
ret = compute_key(key, klen, seed1, slen1);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
LOGE("compute_key error\n");
|
||||
free(key);
|
||||
key = NULL;
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reserve a dir for log storage.
|
||||
*
|
||||
* @param mode Mode for log storage.
|
||||
* @param[out] dir Prefix of dir path reserved.
|
||||
* @param[out] index of dir reserved.
|
||||
*
|
||||
* @return 0 if successful, or -1 if not.
|
||||
*/
|
||||
static int reserve_log_folder(enum e_dir_mode mode, char *dir,
|
||||
unsigned int *current)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
int res;
|
||||
int plen;
|
||||
int dlen;
|
||||
struct sender_t *crashlog;
|
||||
const char *outdir;
|
||||
int maxdirs;
|
||||
|
||||
crashlog = get_sender_by_name("crashlog");
|
||||
if (!crashlog)
|
||||
return -1;
|
||||
|
||||
outdir = crashlog->outdir;
|
||||
|
||||
switch (mode) {
|
||||
case MODE_CRASH:
|
||||
plen = snprintf(path, PATH_MAX, "%s/%s", outdir,
|
||||
CRASH_CURRENT_LOG);
|
||||
dlen = snprintf(dir, PATH_MAX, "%s/%s", outdir, "crashlog");
|
||||
break;
|
||||
case MODE_STATS:
|
||||
plen = snprintf(path, PATH_MAX, "%s/%s", outdir,
|
||||
STATS_CURRENT_LOG);
|
||||
dlen = snprintf(dir, PATH_MAX, "%s/%s", outdir, "stats");
|
||||
break;
|
||||
case MODE_VMEVENT:
|
||||
plen = snprintf(path, PATH_MAX, "%s/%s", outdir,
|
||||
VM_CURRENT_LOG);
|
||||
dlen = snprintf(dir, PATH_MAX, "%s/%s", outdir, "vmevent");
|
||||
break;
|
||||
default:
|
||||
LOGW("Invalid mode %d\n", mode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (s_not_expect(plen, PATH_MAX) || s_not_expect(dlen, PATH_MAX)) {
|
||||
LOGE("the length of path/dir is too long\n");
|
||||
return -1;
|
||||
}
|
||||
/* Read current value in file */
|
||||
res = file_read_int(path, current);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
if (cfg_atoi(crashlog->maxcrashdirs, crashlog->maxcrashdirs_len,
|
||||
&maxdirs) == -1)
|
||||
return -1;
|
||||
if (maxdirs <= 0) {
|
||||
LOGE("failed to reserve dir, maxdirs must be greater than 0\n");
|
||||
return -1;
|
||||
}
|
||||
/* Open file in read/write mode to update the new current */
|
||||
res = file_update_int(path, *current, (unsigned int)maxdirs);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char *cf_line(char *dest, const char *k, size_t klen, const char *v,
|
||||
size_t vlen)
|
||||
{
|
||||
char *t;
|
||||
|
||||
t = mempcpy(dest, k, klen);
|
||||
t = mempcpy(t, v, vlen);
|
||||
return mempcpy(t, "\n", 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a crashfile with given params.
|
||||
*
|
||||
* @param dir Where to generate crashfile.
|
||||
* @param event Event name.
|
||||
* @param hashkey Event id.
|
||||
* @param type Subtype of this event.
|
||||
* @param data* String obtained by get_data.
|
||||
*/
|
||||
void generate_crashfile(const char *dir,
|
||||
const char *event, size_t elen,
|
||||
const char *hashkey, size_t hlen,
|
||||
const char *type, size_t tlen,
|
||||
const char *data0, size_t d0len,
|
||||
const char *data1, size_t d1len,
|
||||
const char *data2, size_t d2len)
|
||||
{
|
||||
char *buf;
|
||||
char *path;
|
||||
char *tail;
|
||||
char datetime[LONG_TIME_SIZE];
|
||||
char uptime[UPTIME_SIZE];
|
||||
int hours;
|
||||
const int fmtsize = 128;
|
||||
size_t ltlen;
|
||||
int n;
|
||||
int filesize;
|
||||
|
||||
if (!dir || !event || !elen || !hashkey || !hlen ||
|
||||
!type || !tlen)
|
||||
return;
|
||||
if (d0len > 0 && !data0)
|
||||
return;
|
||||
if (d1len > 0 && !data1)
|
||||
return;
|
||||
if (d2len > 0 && !data2)
|
||||
return;
|
||||
|
||||
ltlen = get_current_time_long(datetime);
|
||||
if (!ltlen)
|
||||
return;
|
||||
n = get_uptime_string(uptime, &hours);
|
||||
if (n < 0)
|
||||
return;
|
||||
|
||||
filesize = fmtsize + ltlen + n + elen + hlen + tlen + d0len + d1len +
|
||||
d2len + strnlen(guuid, UUID_SIZE) +
|
||||
strnlen(gbuildversion, BUILD_VERSION_SIZE);
|
||||
|
||||
buf = malloc(filesize);
|
||||
if (buf == NULL) {
|
||||
LOGE("out of memory\n");
|
||||
return;
|
||||
}
|
||||
|
||||
tail = cf_line(buf, "EVENT=", 6, event, elen);
|
||||
tail = cf_line(tail, "ID=", 3, hashkey, hlen);
|
||||
tail = cf_line(tail, "DEVICEID=", 9, guuid, strnlen(guuid, UUID_SIZE));
|
||||
tail = cf_line(tail, "DATE=", 5, datetime, ltlen);
|
||||
tail = cf_line(tail, "UPTIME=", 7, uptime, n);
|
||||
tail = cf_line(tail, "BUILD=", 6, gbuildversion,
|
||||
strnlen(gbuildversion, BUILD_VERSION_SIZE));
|
||||
tail = cf_line(tail, "TYPE=", 5, type, tlen);
|
||||
|
||||
if (d0len)
|
||||
tail = cf_line(tail, "DATA0=", 6, data0, d0len);
|
||||
if (d1len)
|
||||
tail = cf_line(tail, "DATA1=", 6, data1, d1len);
|
||||
if (d2len)
|
||||
tail = cf_line(tail, "DATA2=", 6, data2, d2len);
|
||||
tail = mempcpy(tail, "_END\n", 5);
|
||||
*tail = '\0';
|
||||
|
||||
if (asprintf(&path, "%s/crashfile", dir) == -1) {
|
||||
LOGE("out of memory\n");
|
||||
free(buf);
|
||||
return;
|
||||
}
|
||||
|
||||
if (overwrite_file(path, buf) != 0)
|
||||
LOGE("failed to new crashfile (%s), error (%s)\n", path,
|
||||
strerror(errno));
|
||||
|
||||
free(buf);
|
||||
free(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a dir for log storage.
|
||||
*
|
||||
* @param mode Mode for log storage.
|
||||
* @param hashkey Event id.
|
||||
* @param[out] dir_len Length of generated dir.
|
||||
*
|
||||
* @return a pointer to generated path if successful, or NULL if not.
|
||||
*/
|
||||
char *generate_log_dir(enum e_dir_mode mode, char *hashkey, size_t *dir_len)
|
||||
{
|
||||
char *path;
|
||||
char dir[PATH_MAX];
|
||||
unsigned int current;
|
||||
int len;
|
||||
|
||||
if (reserve_log_folder(mode, dir, ¤t))
|
||||
return NULL;
|
||||
|
||||
len = asprintf(&path, "%s%d_%s", dir, current, hashkey);
|
||||
if (len == -1) {
|
||||
LOGE("construct log path failed, out of memory\n");
|
||||
hist_raise_infoerror("DIR CREATE", 10);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mkdir(path, 0777) == -1) {
|
||||
LOGE("Cannot create dir %s\n", path);
|
||||
hist_raise_infoerror("DIR CREATE", 10);
|
||||
free(path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (dir_len)
|
||||
*dir_len = (size_t)len;
|
||||
return path;
|
||||
}
|
||||
|
||||
int is_boot_id_changed(void)
|
||||
{
|
||||
void *boot_id;
|
||||
void *logged_boot_id;
|
||||
char logged_boot_id_path[PATH_MAX];
|
||||
unsigned long size;
|
||||
struct sender_t *crashlog;
|
||||
int res;
|
||||
int result = 1; /* returns changed by default */
|
||||
|
||||
crashlog = get_sender_by_name("crashlog");
|
||||
if (!crashlog)
|
||||
return result;
|
||||
|
||||
res = read_file(BOOTID_NODE, &size, &boot_id);
|
||||
if (res == -1 || !size)
|
||||
return result;
|
||||
|
||||
res = snprintf(logged_boot_id_path, sizeof(logged_boot_id_path),
|
||||
"%s/%s", crashlog->outdir, BOOTID_LOG);
|
||||
if (s_not_expect(res, sizeof(logged_boot_id_path)))
|
||||
goto out;
|
||||
|
||||
if (file_exists(logged_boot_id_path)) {
|
||||
res = read_file(logged_boot_id_path, &size, &logged_boot_id);
|
||||
if (res == -1 || !size)
|
||||
goto out;
|
||||
|
||||
if (!strcmp((char *)logged_boot_id, (char *)boot_id))
|
||||
result = 0;
|
||||
|
||||
free(logged_boot_id);
|
||||
}
|
||||
|
||||
if (result)
|
||||
overwrite_file(logged_boot_id_path, boot_id);
|
||||
out:
|
||||
free(boot_id);
|
||||
return result;
|
||||
}
|
||||
Reference in New Issue
Block a user