1343 lines
34 KiB
C
Raw Normal View History

2019-09-30 10:53:41 -04:00
/******************************************************************************
* Copyright (c) Huawei Technologies Co., Ltd. 2017-2019. All rights reserved.
* iSulad licensed under the Mulan PSL v1.
* You can use this software according to the terms and conditions of the Mulan PSL v1.
* You may obtain a copy of Mulan PSL v1 at:
* http://license.coscl.org.cn/MulanPSL
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
* PURPOSE.
* See the Mulan PSL v1 for more details.
* Author: maoweiyong
* Create: 2017-11-22
* Description: provide system information functions
******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <limits.h>
#include <dirent.h>
#include "error.h"
#include "liblcrd.h"
#include "sysinfo.h"
#include "log.h"
#include "securec.h"
#include "read_file.h"
// Cgroup Item Definition
#define CGROUP_BLKIO_WEIGHT "blkio.weight"
#define CGROUP_BLKIO_WEIGHT_DEVICE "blkio.weight_device"
#define CGROUP_BLKIO_READ_BPS_DEVICE "blkio.throttle.read_bps_device"
#define CGROUP_BLKIO_WRITE_BPS_DEVICE "blkio.throttle.write_bps_device"
#define CGROUP_BLKIO_READ_IOPS_DEVICE "blkio.throttle.read_iops_device"
#define CGROUP_BLKIO_WRITE_IOPS_DEVICE "blkio.throttle.write_iops_device"
#define CGROUP_CPU_SHARES "cpu.shares"
#define CGROUP_CPU_PERIOD "cpu.cfs_period_us"
#define CGROUP_CPU_QUOTA "cpu.cfs_quota_us"
#define CGROUP_CPU_RT_PERIOD "cpu.rt_period_us"
#define CGROUP_CPU_RT_RUNTIME "cpu.rt_runtime_us"
#define CGROUP_CPUSET_CPUS "cpuset.cpus"
#define CGROUP_CPUSET_MEMS "cpuset.mems"
#define CGROUP_MEMORY_LIMIT "memory.limit_in_bytes"
#define CGROUP_MEMORY_SWAP "memory.memsw.limit_in_bytes"
#define CGROUP_MEMORY_SWAPPINESS "memory.swappiness"
#define CGROUP_MEMORY_RESERVATION "memory.soft_limit_in_bytes"
#define CGROUP_KENEL_MEMORY_LIMIT "memory.kmem.limit_in_bytes"
#define CGROUP_MEMORY_OOM_CONTROL "memory.oom_control"
struct layer {
char **controllers;
char *mountpoint;
};
static void free_list(char **str_list)
{
int i;
if (str_list == NULL) {
return;
}
for (i = 0; str_list[i]; i++) {
free(str_list[i]);
str_list[i] = NULL;
}
free(str_list);
}
static void free_layer(struct layer **layers)
{
struct layer **it = NULL;
if (layers == NULL) {
return;
}
for (it = layers; it && *it; it++) {
free((*it)->mountpoint);
(*it)->mountpoint = NULL;
free_list((*it)->controllers);
(*it)->controllers = NULL;
free(*it);
*it = NULL;
}
free(layers);
}
static int add_null_to_list(void ***list)
{
int ret = 0;
size_t index = 0;
size_t newsize, oldsize;
void **newlist = NULL;
if (*list != NULL) {
for (; (*list)[index] != NULL; index++) {
}
}
if (index > SIZE_MAX / sizeof(void **) - 2) {
ERROR("Out of range");
return -1;
}
newsize = (index + 2) * sizeof(void **);
oldsize = index * sizeof(void **);
ret = mem_realloc((void **)&newlist, newsize, (*list), oldsize);
if (ret < 0) {
ERROR("Out of memory");
return -1;
}
*list = newlist;
(*list)[index + 1] = NULL;
return (int)index;
}
static int append_string(char ***list, const char *entry)
{
int index;
char *dup_entry = NULL;
index = add_null_to_list((void ***)list);
if (index < 0) {
return -1;
}
dup_entry = util_strdup_s(entry);
if (dup_entry == NULL) {
return -1;
}
(*list)[index] = dup_entry;
return 0;
}
static int append_subsystem_to_list(char ***klist, char ***nlist, const char *ptoken)
{
int ret = 0;
if (strncmp(ptoken, "name=", 5) == 0) {
ret = append_string(nlist, ptoken);
if (ret != 0) {
ERROR("Failed to append string");
return -1;
}
} else {
ret = append_string(klist, ptoken);
if (ret != 0) {
ERROR("Failed to append string");
return -1;
}
}
return 0;
}
static int get_cgroup_subsystems(char ***klist, char ***nlist)
{
int ret = 0;
size_t length = 0;
FILE *fp = NULL;
char *pline = NULL;
fp = util_fopen("/proc/self/cgroup", "r");
if (fp == NULL) {
return -1;
}
while (getline(&pline, &length, fp) != -1) {
char *pos = NULL;
char *pos2 = NULL;
char *ptoken = NULL;
char *psave = NULL;
pos = strchr(pline, ':');
if (pos == NULL) {
ERROR("Invalid cgroup entry: must contain at least two colons: %s", pline);
ret = -1;
goto out;
}
pos++;
pos2 = strchr(pos, ':');
if (pos2 == NULL) {
ERROR("Invalid cgroup entry: must contain at least two colons: %s", pline);
ret = -1;
goto out;
}
*pos2 = '\0';
if ((pos2 - pos) == 0) {
INFO("Not supported cgroup entry: %s", pline);
continue;
}
for (ptoken = strtok_r(pos, ",", &psave); ptoken; ptoken = strtok_r(NULL, ",", &psave)) {
if (append_subsystem_to_list(klist, nlist, ptoken)) {
goto out;
}
}
}
out:
free(pline);
fclose(fp);
if (ret != 0) {
free_list(*klist);
*klist = NULL;
free_list(*nlist);
*nlist = NULL;
}
return ret;
}
static bool list_contain_string(const char **a_list, const char *str)
{
int i;
if (a_list == NULL) {
return false;
}
for (i = 0; a_list[i]; i++) {
if (strcmp(a_list[i], str) == 0) {
return true;
}
}
return false;
}
static char *cgroup_legacy_must_prefix_named(const char *entry)
{
size_t len;
char *prefixed = NULL;
const char *prefix = "name=";
len = strlen(entry);
if (((SIZE_MAX - len) - 1) < strlen(prefix)) {
ERROR("Out of memory");
return NULL;
}
prefixed = util_common_calloc_s(len + strlen(prefix) + 1);
if (prefixed == NULL) {
ERROR("Out of memory");
return NULL;
}
if (memcpy_s(prefixed, len + strlen(prefix) + 1, prefix, strlen(prefix)) != EOK) {
ERROR("Failed to copy memory!");
free(prefixed);
return NULL;
}
if (memcpy_s(prefixed + strlen(prefix), len + 1, entry, len) != EOK) {
ERROR("Failed to copy memory!");
free(prefixed);
return NULL;
}
prefixed[len + strlen(prefix)] = '\0';
return prefixed;
}
static int append_controller(const char **klist, const char **nlist, char ***clist, const char *entry)
{
int index;
char *dup_entry = NULL;
if (list_contain_string(klist, entry) && list_contain_string(nlist, entry)) {
ERROR("Refusing to use ambiguous controller \"%s\"", entry);
ERROR("It is both a named and kernel subsystem");
return -1;
}
index = add_null_to_list((void ***)clist);
if (index < 0) {
return -1;
}
if (strncmp(entry, "name=", 5) == 0) {
dup_entry = util_strdup_s(entry);
} else if (list_contain_string(klist, entry)) {
dup_entry = util_strdup_s(entry);
} else {
dup_entry = cgroup_legacy_must_prefix_named(entry);
}
if (dup_entry == NULL) {
return -1;
}
(*clist)[index] = dup_entry;
return 0;
}
static inline bool is_cgroup_mountpoint(const char *mp)
{
return strncmp(mp, "/sys/fs/cgroup/", strlen("/sys/fs/cgroup/")) == 0;
}
static void set_char_to_terminator(char *p)
{
*p = '\0';
}
static char **cgroup_get_controllers(const char **klist, const char **nlist, const char *line)
{
int index;
char *dup = NULL;
char *pos2 = NULL;
char *tok = NULL;
const char *pos = line;
char *psave = NULL;
char *sep = ",";
char **pret = NULL;
for (index = 0; index < 4; index++) {
pos = strchr(pos, ' ');
if (pos == NULL) {
ERROR("Invalid mountinfo format \"%s\"", line);
return NULL;
}
pos++;
}
if (!is_cgroup_mountpoint(pos)) {
return NULL;
}
pos += strlen("/sys/fs/cgroup/");
pos2 = strchr(pos, ' ');
if (pos2 == NULL) {
ERROR("Invalid mountinfo format \"%s\"", line);
return NULL;
}
set_char_to_terminator(pos2);
dup = util_strdup_s(pos);
*pos2 = ' ';
for (tok = strtok_r(dup, sep, &psave); tok; tok = strtok_r(NULL, sep, &psave)) {
if (append_controller(klist, nlist, &pret, tok)) {
ERROR("Failed to append controller");
free_list(pret);
pret = NULL;
break;
}
}
free(dup);
return pret;
}
/* add hierarchy */
static int cgroup_add_layer(struct layer ***layers, char **clist, char *mountpoint)
{
int index;
struct layer *newh = NULL;
newh = util_common_calloc_s(sizeof(struct layer));
if (newh == NULL) {
return -1;
}
newh->controllers = clist;
newh->mountpoint = mountpoint;
index = add_null_to_list((void ***)layers);
if (index < 0) {
free(newh);
return -1;
}
(*layers)[index] = newh;
return 0;
}
int cgroup_get_mountpoint_and_root(char *pline, char **mountpoint, char **root)
{
int index;
char *posmp = NULL;
char *posrt = NULL;
char *pos = pline;
// find root
for (index = 0; index < 3; index++) {
pos = strchr(pos, ' ');
if (pos == NULL) {
return -1;
}
pos++;
}
posrt = pos;
// find mountpoint
pos = strchr(pos, ' ');
if (pos == NULL) {
return -1;
}
*pos = '\0';
if (root != NULL) {
*root = util_strdup_s(posrt);
}
pos++;
posmp = pos;
if (!is_cgroup_mountpoint(posmp)) {
return -1;
}
pos = strchr(pos + strlen("/sys/fs/cgroup/"), ' ');
if (pos == NULL) {
return -1;
}
*pos = '\0';
if (mountpoint != NULL) {
*mountpoint = util_strdup_s(posmp);
}
return 0;
}
static bool lists_intersect(const char **controllers, const char **list)
{
int index;
if (controllers == NULL || list == NULL) {
return false;
}
for (index = 0; controllers[index]; index++) {
if (list_contain_string(list, controllers[index])) {
return true;
}
}
return false;
}
static bool controller_list_is_dup(struct layer **llist, const char **clist)
{
int index;
if (llist == NULL) {
return false;
}
for (index = 0; llist[index]; index++) {
if (lists_intersect((const char **)llist[index]->controllers, (const char **)clist)) {
return true;
}
}
return false;
}
static struct layer **cgroup_layers_find(void)
{
int nret;
FILE *fp = NULL;
size_t length = 0;
char *pline = NULL;
char **klist = NULL;
char **nlist = NULL;
struct layer **layers = NULL;
nret = get_cgroup_subsystems(&klist, &nlist);
if (nret < 0) {
ERROR("Failed to retrieve available legacy cgroup controllers\n");
return NULL;
}
fp = util_fopen("/proc/self/mountinfo", "r");
if (fp == NULL) {
ERROR("Failed to open \"/proc/self/mountinfo\"\n");
goto out;
}
while (getline(&pline, &length, fp) != -1) {
char *mountpoint = NULL;
char **clist = NULL;
int mret;
clist = cgroup_get_controllers((const char **)klist, (const char **)nlist, pline);
if (clist == NULL) {
goto list_out;
}
if (controller_list_is_dup(layers, (const char **)clist)) {
goto list_out;
}
mret = cgroup_get_mountpoint_and_root(pline, &mountpoint, NULL);
if (mret != 0 || mountpoint == NULL) {
ERROR("Failed parsing mountpoint from \"%s\"\n", pline);
goto list_out;
}
nret = cgroup_add_layer(&layers, clist, mountpoint);
if (nret != 0) {
ERROR("Failed to add hierarchies");
goto list_out;
}
continue;
list_out:
free_list(clist);
free(mountpoint);
}
out:
free_list(klist);
free_list(nlist);
if (fp != NULL) {
fclose(fp);
}
free(pline);
return layers;
}
/* cgroup enabled */
static bool cgroup_enabled(const char *mountpoint, const char *name)
{
char path[PATH_MAX] = { 0 };
int nret;
nret = sprintf_s(path, sizeof(path), "%s/%s", mountpoint, name);
if (nret < 0) {
ERROR("Path is too long");
return false;
}
return util_file_exists(path);
}
static char *cgroup_get_pagesize(const char *pline)
{
size_t headlen;
char *pos2 = NULL;
const char *pos = pline;
headlen = strlen("Hugepagesize");
if (strncmp(pos, "Hugepagesize", headlen) != 0) {
return NULL;
}
pos2 = strchr(pos + headlen, ':');
if (pos2 == NULL) {
ERROR("Invalid Hugepagesize format \"%s\"", pline);
return NULL;
}
*pos2 = '\0';
pos2++;
return util_string_delchar(pos2, ' ');
}
/* get default huge page size */
char *get_default_huge_page_size(void)
{
int ret = 0;
int64_t sizenum = 0;
size_t length = 0;
FILE *fp = NULL;
char *pagesize = NULL;
char *humansize = NULL;
char *pline = NULL;
fp = util_fopen("/proc/meminfo", "r");
if (fp == NULL) {
ERROR("Failed to open \"/proc/meminfo\"\n");
return NULL;
}
while (getline(&pline, &length, fp) != -1) {
pagesize = cgroup_get_pagesize(pline);
if (pagesize != NULL) {
break;
}
}
if (pagesize == NULL) {
ERROR("Failed to get hugepage size");
goto out;
}
util_trim_newline(pagesize);
ret = util_parse_byte_size_string(pagesize, &sizenum);
if (ret != 0) {
ERROR("Invalid page size: %s", pagesize);
goto out;
}
humansize = util_human_size((uint64_t)sizenum);
out:
fclose(fp);
free(pagesize);
free(pline);
return humansize;
}
/* get default total mem size */
uint64_t get_default_total_mem_size(void)
{
FILE *fp = NULL;
size_t len = 0;
char *line = NULL;
char *p = NULL;
uint64_t sysmem_limit = 0;
fp = util_fopen("/proc/meminfo", "r");
if (fp == NULL) {
ERROR("Failed to open /proc/meminfo: %s", strerror(errno));
return sysmem_limit;
}
while (getline(&line, &len, fp) != -1) {
p = strchr(line, ' ');
if (p == NULL) {
goto out;
}
*p = '\0';
p++;
if (strcmp(line, "MemTotal:") == 0) {
while (*p == ' ' || *p == '\t') {
p++;
}
if (*p == '\0') {
goto out;
}
sysmem_limit = strtoull(p, NULL, 0);
break;
}
}
out:
fclose(fp);
free(line);
return sysmem_limit * SIZE_KB;
}
/* get default operating system */
char *get_operating_system(void)
{
size_t len = 0;
FILE *fp;
char *prettyname = NULL;
char *pretty_name = "PRETTY_NAME=";
char *line = NULL;
fp = fopen(etcOsRelease, "r");
if (fp == NULL) {
INFO("Failed to open %s :%s", etcOsRelease, strerror(errno));
fp = fopen(altOsRelease, "r");
if (fp == NULL) {
ERROR("Failed to open %s :%s", altOsRelease, strerror(errno));
goto out;
}
}
while (getline(&line, &len, fp) != -1) {
if ((strncmp(line, pretty_name, strlen(pretty_name))) == 0) {
prettyname = util_strdup_s(line + strlen(pretty_name));
break;
}
}
prettyname = util_trim_quotation(prettyname);
out:
if (fp != NULL) {
fclose(fp);
}
free(line);
if (prettyname != NULL) {
return prettyname;
}
return util_strdup_s("Linux");
}
static void cgroup_do_log(bool quiet, bool do_log, const char *msg)
{
if (!quiet && do_log) {
WARN("%s", msg);
}
}
static char *find_cgroup_subsystem_mountpoint(struct layer **layers, const char *subsystem)
{
struct layer **it = NULL;
for (it = layers; it && *it; it++) {
char **cit = NULL;
for (cit = (*it)->controllers; cit && *cit; cit++) {
if (strcmp(*cit, subsystem) == 0) {
return (*it)->mountpoint;
}
}
}
return NULL;
}
/* check cgroup mem */
static void check_cgroup_mem(struct layer **layers, bool quiet, cgroup_mem_info_t *meminfo)
{
char *mountpoint = NULL;
mountpoint = find_cgroup_subsystem_mountpoint(layers, "memory");
if (mountpoint == NULL) {
cgroup_do_log(quiet, true, "Your kernel does not support cgroup memory limit");
return;
}
meminfo->limit = true;
meminfo->swap = cgroup_enabled(mountpoint, CGROUP_MEMORY_SWAP);
cgroup_do_log(quiet, !(meminfo->swap), "Your kernel does not support swap memory limit");
meminfo->reservation = cgroup_enabled(mountpoint, CGROUP_MEMORY_RESERVATION);
cgroup_do_log(quiet, !(meminfo->reservation), "Your kernel does not support memory reservation");
meminfo->oomkilldisable = cgroup_enabled(mountpoint, CGROUP_MEMORY_OOM_CONTROL);
cgroup_do_log(quiet, !(meminfo->oomkilldisable), "Your kernel does not support oom control");
meminfo->swappiness = cgroup_enabled(mountpoint, CGROUP_MEMORY_SWAPPINESS);
cgroup_do_log(quiet, !(meminfo->swappiness), "Your kernel does not support memory swappiness");
meminfo->kernel = cgroup_enabled(mountpoint, CGROUP_KENEL_MEMORY_LIMIT);
cgroup_do_log(quiet, !(meminfo->kernel), "Your kernel does not support kernel memory limit");
}
/* check cgroup cpu */
static void check_cgroup_cpu(struct layer **layers, bool quiet, cgroup_cpu_info_t *cpuinfo)
{
char *mountpoint = NULL;
mountpoint = find_cgroup_subsystem_mountpoint(layers, "cpu");
if (mountpoint == NULL) {
cgroup_do_log(quiet, true, "Unable to find cpu cgroup in mounts");
return;
}
cpuinfo->cpu_rt_period = cgroup_enabled(mountpoint, CGROUP_CPU_RT_PERIOD);
cgroup_do_log(quiet, !(cpuinfo->cpu_rt_period), "Your kernel does not support cgroup rt period");
cpuinfo->cpu_rt_runtime = cgroup_enabled(mountpoint, CGROUP_CPU_RT_RUNTIME);
cgroup_do_log(quiet, !(cpuinfo->cpu_rt_runtime), "Your kernel does not support cgroup rt runtime");
cpuinfo->cpu_shares = cgroup_enabled(mountpoint, CGROUP_CPU_SHARES);
cgroup_do_log(quiet, !(cpuinfo->cpu_shares), "Your kernel does not support cgroup cpu shares");
cpuinfo->cpu_cfs_period = cgroup_enabled(mountpoint, CGROUP_CPU_PERIOD);
cgroup_do_log(quiet, !(cpuinfo->cpu_cfs_period), "Your kernel does not support cgroup cfs period");
cpuinfo->cpu_cfs_quota = cgroup_enabled(mountpoint, CGROUP_CPU_QUOTA);
cgroup_do_log(quiet, !(cpuinfo->cpu_cfs_quota), "Your kernel does not support cgroup cfs quota");
}
/* check cgroup blkio info */
static void check_cgroup_blkio_info(struct layer **layers, bool quiet, cgroup_blkio_info_t *blkioinfo)
{
char *mountpoint = NULL;
mountpoint = find_cgroup_subsystem_mountpoint(layers, "blkio");
if (mountpoint == NULL) {
cgroup_do_log(quiet, true, "Unable to find blkio cgroup in mounts");
return;
}
blkioinfo->blkio_weight = cgroup_enabled(mountpoint, CGROUP_BLKIO_WEIGHT);
cgroup_do_log(quiet, !(blkioinfo->blkio_weight), "Your kernel does not support cgroup blkio weight");
blkioinfo->blkio_weight_device = cgroup_enabled(mountpoint, CGROUP_BLKIO_WEIGHT_DEVICE);
cgroup_do_log(quiet, !(blkioinfo->blkio_weight_device), "Your kernel does not support cgroup blkio weight_device");
blkioinfo->blkio_read_bps_device = cgroup_enabled(mountpoint, CGROUP_BLKIO_READ_BPS_DEVICE);
cgroup_do_log(quiet, !(blkioinfo->blkio_read_bps_device),
"Your kernel does not support cgroup blkio throttle.read_bps_device");
blkioinfo->blkio_write_bps_device = cgroup_enabled(mountpoint, CGROUP_BLKIO_WRITE_BPS_DEVICE);
cgroup_do_log(quiet, !(blkioinfo->blkio_write_bps_device),
"Your kernel does not support cgroup blkio throttle.write_bps_device");
blkioinfo->blkio_read_iops_device = cgroup_enabled(mountpoint, CGROUP_BLKIO_READ_IOPS_DEVICE);
cgroup_do_log(quiet, !(blkioinfo->blkio_read_iops_device),
"Your kernel does not support cgroup blkio throttle.read_iops_device");
blkioinfo->blkio_write_iops_device = cgroup_enabled(mountpoint, CGROUP_BLKIO_WRITE_IOPS_DEVICE);
cgroup_do_log(quiet, !(blkioinfo->blkio_write_iops_device),
"Your kernel does not support cgroup blkio throttle.write_iops_device");
}
/* check cgroup cpuset info */
static void check_cgroup_cpuset_info(struct layer **layers, bool quiet, cgroup_cpuset_info_t *cpusetinfo)
{
size_t file_size = 0;
errno_t nret = EOK;
char *mountpoint = NULL;
char cpuset_cpus_path[PATH_MAX] = { 0 };
char cpuset_mems_path[PATH_MAX] = { 0 };
mountpoint = find_cgroup_subsystem_mountpoint(layers, "cpuset");
if (mountpoint == NULL) {
cgroup_do_log(quiet, true, ("Unable to find cpuset cgroup in mounts"));
return;
}
nret = sprintf_s(cpuset_cpus_path, sizeof(cpuset_cpus_path), "%s/%s", mountpoint, CGROUP_CPUSET_CPUS);
if (nret < 0) {
ERROR("Path is too long");
goto error;
}
cpusetinfo->cpus = read_file(cpuset_cpus_path, &file_size);
if (cpusetinfo->cpus == NULL) {
ERROR("Failed to read the file: %s", cpuset_cpus_path);
goto error;
}
nret = sprintf_s(cpuset_mems_path, sizeof(cpuset_mems_path), "%s/%s", mountpoint, CGROUP_CPUSET_MEMS);
if (nret < 0) {
ERROR("Path is too long");
goto error;
}
cpusetinfo->mems = read_file(cpuset_mems_path, &file_size);
if (cpusetinfo->mems == NULL) {
ERROR("Failed to read the file: %s", cpuset_mems_path);
goto error;
}
cpusetinfo->cpus = util_trim_space(cpusetinfo->cpus);
cpusetinfo->mems = util_trim_space(cpusetinfo->mems);
cpusetinfo->cpuset = true;
return;
error:
free(cpusetinfo->cpus);
cpusetinfo->cpus = NULL;
free(cpusetinfo->mems);
cpusetinfo->mems = NULL;
}
/* check cgroup pids */
static void check_cgroup_pids(bool quiet, cgroup_pids_info_t *pidsinfo)
{
int ret = 0;
char *pidsmp = NULL;
ret = find_cgroup_mountpoint_and_root("pids", &pidsmp, NULL);
if (ret != 0 || pidsmp == NULL) {
if (!quiet) {
WARN("Unable to find pids cgroup in mounts");
}
goto out;
}
pidsinfo->pidslimit = true;
out:
free(pidsmp);
}
/* check cgroup files */
static void check_cgroup_files(bool quiet, cgroup_files_info_t *filesinfo)
{
int ret = 0;
char *filesmp = NULL;
ret = find_cgroup_mountpoint_and_root("files", &filesmp, NULL);
if (ret != 0 || filesmp == NULL) {
if (!quiet) {
WARN("Unable to find pids cgroup in mounts");
}
goto out;
}
filesinfo->fileslimit = true;
out:
free(filesmp);
}
/* find cgroup mountpoint and root */
int find_cgroup_mountpoint_and_root(const char *subsystem, char **mountpoint, char **root)
{
int ret = 0;
FILE *fp = NULL;
size_t length = 0;
char *pline = NULL;
fp = util_fopen("/proc/self/mountinfo", "r");
if (fp == NULL) {
ERROR("Failed to open \"/proc/self/mountinfo\"\n");
ret = -1;
goto free_out;
}
while (getline(&pline, &length, fp) != -1) {
char *dup = NULL;
char *p = NULL;
char *tok = NULL;
char *mp = NULL;
char *rt = NULL;
char *saveptr = NULL;
char *sep = ",";
int mret;
mret = cgroup_get_mountpoint_and_root(pline, &mp, &rt);
if (mret != 0 || mp == NULL || rt == NULL) {
goto mp_out;
}
p = mp;
p += strlen("/sys/fs/cgroup/");
dup = util_strdup_s(p);
if (dup == NULL) {
ERROR("Out of memory");
free(mp);
ret = -1;
goto free_out;
}
for (tok = strtok_r(dup, sep, &saveptr); tok; tok = strtok_r(NULL, sep, &saveptr)) {
if (strcmp(tok, subsystem) != 0) {
continue;
}
if (mountpoint != NULL) {
*mountpoint = mp;
} else {
free(mp);
}
if (root != NULL) {
*root = rt;
} else {
free(rt);
}
free(dup);
goto free_out;
}
free(dup);
mp_out:
free(mp);
free(rt);
continue;
}
free_out:
if (fp != NULL) {
fclose(fp);
}
free(pline);
return ret;
}
/* check cgroup hugetlb */
static void check_cgroup_hugetlb(struct layer **layers, bool quiet, cgroup_hugetlb_info_t *hugetlbinfo)
{
int nret;
char *mountpoint = NULL;
char *defaultpagesize = NULL;
char hugetlbpath[64] = { 0x00 };
mountpoint = find_cgroup_subsystem_mountpoint(layers, "hugetlb");
if (mountpoint == NULL) {
cgroup_do_log(quiet, true, "Your kernel does not support cgroup hugetlb limit");
return;
}
defaultpagesize = get_default_huge_page_size();
if (defaultpagesize == NULL) {
WARN("Your kernel does not support cgroup hugetlb limit");
return;
}
nret = sprintf_s(hugetlbpath, sizeof(hugetlbpath), "hugetlb.%s.limit_in_bytes", defaultpagesize);
if (nret < 0) {
WARN("Failed to print hugetlb path");
goto free_out;
}
hugetlbinfo->hugetlblimit = cgroup_enabled(mountpoint, hugetlbpath);
cgroup_do_log(quiet, !hugetlbinfo->hugetlblimit, ("Your kernel does not support hugetlb limit"));
free_out:
free(defaultpagesize);
}
/* get huge page sizes */
static char **get_huge_page_sizes()
{
int index;
int ret = 0;
char *hugetlbmp = NULL;
char **hps = NULL;
DIR *dir = NULL;
struct dirent *info_archivo = NULL;
ret = find_cgroup_mountpoint_and_root("hugetlb", &hugetlbmp, NULL);
if (ret != 0 || hugetlbmp == NULL) {
ERROR("Hugetlb cgroup not supported");
return NULL;
}
dir = opendir(hugetlbmp);
if (dir == NULL) {
ERROR("Failed to open hugetlb cgroup directory: %s", hugetlbmp);
goto free_out;
}
info_archivo = readdir(dir);
for (; info_archivo != NULL; info_archivo = readdir(dir)) {
char *contain = NULL;
char *dup = NULL;
char *pos = NULL;
char *dot2 = NULL;
contain = strstr(info_archivo->d_name, "limit_in_bytes");
if (contain == NULL) {
continue;
}
dup = util_strdup_s(info_archivo->d_name);
if (dup == NULL) {
goto free_out;
}
pos = dup;
pos = strchr(pos, '.');
if (pos == NULL) {
goto dup_free;
}
*pos = '\0';
pos++;
dot2 = strchr(pos, '.');
if (dot2 == NULL) {
goto dup_free;
}
*dot2 = '\0';
index = add_null_to_list((void ***)&hps);
if (index < 0) {
free(dup);
free_list(hps);
hps = NULL;
goto free_out;
}
hps[index] = util_strdup_s(pos);
dup_free:
free(dup);
continue;
}
free_out:
free(hugetlbmp);
if (dir != NULL) {
closedir(dir);
}
return hps;
}
/* is huge pagesize valid */
static bool is_huge_pagesize_valid(const char *pagesize)
{
int nret;
bool bret = false;
size_t hps_len;
char **hps = NULL;
char **it = NULL;
char hpsbuf[BUFSIZ] = { 0 };
hps = get_huge_page_sizes();
if (hps == NULL) {
ERROR("Hugetlb cgroup not supported");
goto free_out;
}
2019-11-06 19:33:20 +08:00
hps_len = util_array_len((const char **)hps);
2019-09-30 10:53:41 -04:00
if (hps_len == 0) {
ERROR("Hugetlb cgroup not supported");
goto free_out;
}
for (it = hps; *it; it++) {
nret = sprintf_s(hpsbuf, sizeof(hpsbuf), "%s ", *it);
if (nret < 0) {
ERROR("hps buf is too short");
goto free_out;
}
if (strcmp(*it, pagesize) == 0) {
bret = true;
}
}
hpsbuf[strlen(hpsbuf) - 1] = '\0';
free_out:
if (!bret) {
ERROR("Invalid hugepage size: %s, should be one of [%s]", pagesize, hpsbuf);
lcrd_set_error_message("Invalid hugepage size: %s, should be one of [%s]", pagesize, hpsbuf);
if (g_lcrd_errmsg == NULL) {
ERROR("Out of memory");
}
}
free_list(hps);
return bret;
}
// isHugeLimitValid check whether input hugetlb limit legal
// it will check whether the limit size is times of size
static void is_hugelimit_valid(const char *pagesize, uint64_t limit)
{
int ret;
int64_t sizeint = 0;
ret = util_parse_byte_size_string(pagesize, &sizeint);
if (ret < 0 || !sizeint) {
WARN("Invalid pagesize: %s", pagesize);
return;
}
if (limit % (uint64_t)sizeint != 0) {
WARN("HugeTlb limit should be times of hugepage size. "
"cgroup will down round to the nearest multiple");
}
}
// check whether hugetlb pagesize and limit legal
char *validate_hugetlb(const char *pagesize, uint64_t limit)
{
char *newpagesize = NULL;
int64_t sizeint = 0;
if (pagesize != NULL && strlen(pagesize)) {
int nret = util_parse_byte_size_string(pagesize, &sizeint);
if (nret < 0) {
ERROR("Invalid pagesize: %s", pagesize);
return NULL;
}
newpagesize = util_human_size((uint64_t)sizeint);
if (newpagesize == NULL) {
ERROR("Invalid pagesize: %s", pagesize);
return NULL;
}
bool valid = is_huge_pagesize_valid(newpagesize);
if (!valid) {
free(newpagesize);
return NULL;
}
} else {
newpagesize = get_default_huge_page_size();
if (newpagesize == NULL) {
ERROR("Failed to get system hugepage size");
return NULL;
}
}
is_hugelimit_valid(newpagesize, limit);
return newpagesize;
}
/* free sysinfo */
void free_sysinfo(sysinfo_t *sysinfo)
{
if (sysinfo == NULL) {
return;
}
free(sysinfo->cpusetinfo.cpus);
sysinfo->cpusetinfo.cpus = NULL;
free(sysinfo->cpusetinfo.mems);
sysinfo->cpusetinfo.mems = NULL;
free(sysinfo);
}
/* get sys info */
sysinfo_t *get_sys_info(bool quiet)
{
struct layer **layers = NULL;
sysinfo_t *sysinfo = NULL;
bool ret = true;
sysinfo = util_common_calloc_s(sizeof(sysinfo_t));
if (sysinfo == NULL) {
ERROR("Out of memory");
return NULL;
}
layers = cgroup_layers_find();
if (layers == NULL) {
ERROR("Failed to parse cgroup information");
ret = false;
goto out;
}
check_cgroup_mem(layers, quiet, &sysinfo->cgmeminfo);
check_cgroup_cpu(layers, quiet, &sysinfo->cgcpuinfo);
check_cgroup_hugetlb(layers, quiet, &sysinfo->hugetlbinfo);
check_cgroup_blkio_info(layers, quiet, &sysinfo->blkioinfo);
check_cgroup_cpuset_info(layers, quiet, &sysinfo->cpusetinfo);
check_cgroup_pids(quiet, &sysinfo->pidsinfo);
check_cgroup_files(quiet, &sysinfo->filesinfo);
out:
free_layer(layers);
if (!ret) {
free_sysinfo(sysinfo);
sysinfo = NULL;
}
return sysinfo;
}
/* free mount info */
void free_mount_info(mountinfo_t *info)
{
if (info == NULL) {
return;
}
free(info->root);
info->root = NULL;
free(info->mountpoint);
info->mountpoint = NULL;
free(info->opts);
info->opts = NULL;
free(info->optional);
info->optional = NULL;
free(info->fstype);
info->fstype = NULL;
free(info->source);
info->source = NULL;
free(info->vfsopts);
info->vfsopts = NULL;
free(info);
}
mountinfo_t *get_mount_info(const char *pline)
{
size_t length;
int ret = 0;
mountinfo_t *info = NULL;
char **list = NULL;
info = util_common_calloc_s(sizeof(mountinfo_t));
if (info == NULL) {
ERROR("Out of memory");
return NULL;
}
list = util_string_split(pline, ' ');
if (list == NULL) {
ERROR("Out of memory");
ret = -1;
goto free_out;
}
2019-11-06 19:33:20 +08:00
length = util_array_len((const char **)list);
2019-09-30 10:53:41 -04:00
if (length < 8) {
ERROR("Invalid mountinfo '%s'", pline);
ret = -1;
goto free_out;
}
info->mountpoint = util_strdup_s(list[4]);
if (strcmp(list[6], "-")) {
info->optional = util_strdup_s(list[6]);
}
free_out:
util_free_array(list);
if (ret != 0) {
free_mount_info(info);
info = NULL;
}
return info;
}
/* free mounts info */
void free_mounts_info(mountinfo_t **minfos)
{
mountinfo_t **it = NULL;
if (minfos == NULL) {
return;
}
for (it = minfos; it && *it; it++) {
free_mount_info(*it);
*it = NULL;
}
free(minfos);
}
/* find mount info */
mountinfo_t *find_mount_info(mountinfo_t **minfos, const char *dir)
{
mountinfo_t **it = NULL;
for (it = minfos; it && *it; it++) {
if ((*it)->mountpoint && !strcmp((*it)->mountpoint, dir)) {
return *it;
}
}
return NULL;
}
/* getmountsinfo */
mountinfo_t **getmountsinfo(void)
{
mountinfo_t **minfos = NULL;
int ret = 0;
FILE *fp = NULL;
size_t length;
char *pline = NULL;
fp = util_fopen("/proc/self/mountinfo", "r");
if (fp == NULL) {
ERROR("Failed to open \"/proc/self/mountinfo\"\n");
return NULL;
}
while (getline(&pline, &length, fp) != -1) {
int index;
mountinfo_t *info;
info = get_mount_info(pline);
if (info == NULL) {
ret = -1;
goto free_out;
}
index = add_null_to_list((void ***)&minfos);
if (index < 0) {
free_mount_info(info);
ret = -1;
goto free_out;
}
minfos[index] = info;
}
free_out:
fclose(fp);
free(pline);
if (ret != 0) {
free_mounts_info(minfos);
minfos = NULL;
}
return minfos;
}
2019-11-06 19:33:20 +08:00