808 lines
21 KiB
C
808 lines
21 KiB
C
/******************************************************************************
|
|
* 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: tanyifeng
|
|
* Create: 2017-11-22
|
|
* Description: provide command functions
|
|
******************************************************************************/
|
|
|
|
#define _GNU_SOURCE
|
|
#include "commander.h"
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include <regex.h>
|
|
#include <limits.h>
|
|
#include "libisulad.h"
|
|
|
|
#include "utils.h"
|
|
#include "log.h"
|
|
|
|
void command_help_isulad_head()
|
|
{
|
|
fprintf(stdout, "isulad\n\nlightweight container runtime daemon\n");
|
|
}
|
|
|
|
int compare_options(const void *s1, const void *s2)
|
|
{
|
|
return strcmp((*(const command_option_t *)s1).large, (*(const command_option_t *)s2).large);
|
|
}
|
|
void print_options(int options_len, const command_option_t *options)
|
|
{
|
|
int i = 0;
|
|
int max_opt_len = 0;
|
|
|
|
for (i = 0; i < options_len; i++) {
|
|
command_option_t option = options[i];
|
|
// -s
|
|
int len = 2;
|
|
// -s, --large, 6 is the length of "-s, --".
|
|
if (option.large != NULL) {
|
|
len = (int)(strlen(option.large) + 6);
|
|
}
|
|
if (len > max_opt_len) {
|
|
max_opt_len = len;
|
|
}
|
|
}
|
|
|
|
// format: " -s, --large description"
|
|
// 6 is the total length of black before "-s" and "description"
|
|
max_opt_len += 6;
|
|
|
|
for (i = 0; i < options_len; i++) {
|
|
command_option_t option = options[i];
|
|
int curindex = 0;
|
|
int space_left = 0;
|
|
|
|
curindex = fprintf(stdout, " ");
|
|
if (option.small) {
|
|
curindex += fprintf(stdout, "-%c", (char)option.small);
|
|
}
|
|
|
|
if (option.large != NULL) {
|
|
if (option.small) {
|
|
curindex += fprintf(stdout, ", --%s", option.large);
|
|
} else {
|
|
curindex += fprintf(stdout, " --%s", option.large);
|
|
}
|
|
}
|
|
|
|
if (curindex <= max_opt_len) {
|
|
space_left = max_opt_len - curindex;
|
|
}
|
|
|
|
fprintf(stdout, "%*s%s\n", space_left, "", option.description);
|
|
}
|
|
fputc('\n', stdout);
|
|
}
|
|
|
|
void command_help(command_t *self)
|
|
{
|
|
const char *progname = strrchr(self->name, '/');
|
|
if (progname == NULL) {
|
|
progname = self->name;
|
|
} else {
|
|
progname++;
|
|
}
|
|
|
|
if (self->type != NULL && strcmp(self->type, "isulad") == 0) {
|
|
command_help_isulad_head();
|
|
}
|
|
fprintf(stdout, "\nUsage: %s %s\n\n", progname, self->usage);
|
|
fprintf(stdout, "%s\n\n", self->description);
|
|
qsort(self->options, (size_t)self->option_count, sizeof(self->options[0]), compare_options);
|
|
print_options(self->option_count, self->options);
|
|
}
|
|
|
|
int command_valid_socket(command_option_t *option, const char *arg)
|
|
{
|
|
if (!util_validate_socket(arg)) {
|
|
COMMAND_ERROR("Invalid socket name : %s", arg);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void command_init(command_t *self, command_option_t *opts, int opts_len, int argc, const char **argv,
|
|
const char *description, const char *usage)
|
|
{
|
|
(void)memset(self, 0, sizeof(command_t));
|
|
self->name = argv[0];
|
|
self->argc = argc - 2;
|
|
self->argv = argv + 2;
|
|
self->usage = usage;
|
|
self->description = description;
|
|
self->options = opts;
|
|
self->option_count = opts_len;
|
|
}
|
|
|
|
void command_option(command_t *self, command_option_type_t type, void *data, int small, const char *large,
|
|
const char *desc, command_callback_t cb)
|
|
{
|
|
if (self->option_count == COMMANDER_MAX_OPTIONS) {
|
|
COMMAND_ERROR("Maximum option definitions exceeded");
|
|
exit(EINVALIDARGS);
|
|
}
|
|
int n = self->option_count++;
|
|
command_option_t *opt = &self->options[n];
|
|
opt->type = type;
|
|
opt->data = data;
|
|
opt->cb = cb;
|
|
opt->small = small;
|
|
opt->description = desc;
|
|
opt->large = large;
|
|
}
|
|
|
|
static int read_option_arg(command_t *self, command_option_t *opt, const char **opt_arg, const char **readed)
|
|
{
|
|
if (self == NULL || opt == NULL || opt_arg == NULL) {
|
|
return -1;
|
|
}
|
|
if (opt->hasdata) {
|
|
*readed = *opt_arg;
|
|
*opt_arg = NULL;
|
|
}
|
|
if (!opt->hasdata && self->argc > 1) {
|
|
opt->hasdata = true;
|
|
*readed = *++self->argv;
|
|
self->argc--;
|
|
}
|
|
if (!opt->hasdata) {
|
|
COMMAND_ERROR("Flag needs an argument: --%s", opt->large);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int command_get_bool_option_data(command_option_t *option, const char **opt_arg)
|
|
{
|
|
bool converted_bool = (option->type == CMD_OPT_TYPE_BOOL) ? true : false;
|
|
|
|
if (option->hasdata) {
|
|
int ret = util_str_to_bool(*opt_arg, &converted_bool);
|
|
if (ret != 0) {
|
|
COMMAND_ERROR("Invalid boolean value \"%s\" for flag --%s", *opt_arg, option->large);
|
|
return -1;
|
|
}
|
|
*opt_arg = NULL;
|
|
}
|
|
|
|
*(bool *)option->data = converted_bool;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int command_get_string_option_data(command_t *self, command_option_t *option, const char **opt_arg)
|
|
{
|
|
if (read_option_arg(self, option, opt_arg, (const char **)option->data)) {
|
|
return -1;
|
|
}
|
|
if (option->cb != NULL) {
|
|
return option->cb(option, *(char **)option->data);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int command_get_string_dup_option_data(command_t *self, command_option_t *option, const char **opt_arg)
|
|
{
|
|
const char *readed_item = NULL;
|
|
|
|
if (read_option_arg(self, option, opt_arg, &readed_item) != 0) {
|
|
return -1;
|
|
}
|
|
if (*(char **)option->data != NULL) {
|
|
free(*(char **)option->data);
|
|
}
|
|
*(char **)option->data = util_strdup_s(readed_item);
|
|
if (option->cb != NULL) {
|
|
return option->cb(option, readed_item);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int command_get_callback_option_data(command_t *self, command_option_t *option, const char **opt_arg)
|
|
{
|
|
const char *readed_item = NULL;
|
|
|
|
if (read_option_arg(self, option, opt_arg, &readed_item)) {
|
|
return -1;
|
|
}
|
|
if (option->cb == NULL) {
|
|
COMMAND_ERROR("Must specify callback for type array");
|
|
return -1;
|
|
}
|
|
return option->cb(option, readed_item);
|
|
}
|
|
|
|
static int command_get_option_data(command_t *self, command_option_t *option, const char **opt_arg)
|
|
{
|
|
if (option == NULL) {
|
|
return -1;
|
|
}
|
|
switch (option->type) {
|
|
case CMD_OPT_TYPE_BOOL:
|
|
case CMD_OPT_TYPE_BOOL_FALSE:
|
|
return command_get_bool_option_data(option, opt_arg);
|
|
case CMD_OPT_TYPE_STRING:
|
|
return command_get_string_option_data(self, option, opt_arg);
|
|
case CMD_OPT_TYPE_STRING_DUP:
|
|
return command_get_string_dup_option_data(self, option, opt_arg);
|
|
case CMD_OPT_TYPE_CALLBACK:
|
|
return command_get_callback_option_data(self, option, opt_arg);
|
|
default:
|
|
COMMAND_ERROR("Unkown command option type:%d", (int)(option->type));
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
int have_short_options(command_t *self, char arg)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < self->option_count; i++) {
|
|
if (self->options[i].small == arg) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static int command_parse_options(command_t *self, const char **opt_arg, bool *found)
|
|
{
|
|
int j = 0;
|
|
|
|
for (j = 0; j < self->option_count; ++j) {
|
|
command_option_t *opt = &self->options[j];
|
|
opt->hasdata = false;
|
|
if (opt->small != (*opt_arg)[0]) {
|
|
continue;
|
|
}
|
|
// match flag
|
|
*found = true;
|
|
if ((*opt_arg)[1]) {
|
|
if ((*opt_arg)[1] == '=') {
|
|
*opt_arg = *opt_arg + 2;
|
|
opt->hasdata = true;
|
|
} else {
|
|
*opt_arg = *opt_arg + 1;
|
|
}
|
|
} else {
|
|
*opt_arg = NULL;
|
|
}
|
|
if (command_get_option_data(self, opt, opt_arg)) {
|
|
return -1;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int command_parse_short_arg(command_t *self, const char *arg)
|
|
{
|
|
bool found = false;
|
|
const char *opt_arg = arg;
|
|
|
|
do {
|
|
found = false;
|
|
if (command_parse_options(self, &opt_arg, &found)) {
|
|
return -1;
|
|
}
|
|
} while (found && opt_arg != NULL);
|
|
|
|
if (opt_arg != NULL) {
|
|
COMMAND_ERROR("Unkown flag found:'%c'", opt_arg[0]);
|
|
exit(EINVALIDARGS);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int command_parse_long_arg(command_t *self, const char *arg)
|
|
{
|
|
int j = 0;
|
|
|
|
if (strcmp(arg, "help") == 0) {
|
|
command_help(self);
|
|
exit(0);
|
|
}
|
|
|
|
for (j = 0; j < self->option_count; ++j) {
|
|
command_option_t *opt = &self->options[j];
|
|
const char *opt_arg = NULL;
|
|
opt->hasdata = false;
|
|
|
|
if (opt->large == NULL) {
|
|
continue;
|
|
}
|
|
|
|
opt_arg = str_skip_str(arg, opt->large);
|
|
if (opt_arg == NULL) {
|
|
continue;
|
|
}
|
|
|
|
if (opt_arg[0]) {
|
|
if (opt_arg[0] != '=') {
|
|
continue;
|
|
}
|
|
opt_arg = opt_arg + 1;
|
|
opt->hasdata = true;
|
|
} else {
|
|
opt_arg = NULL;
|
|
}
|
|
if (command_get_option_data(self, opt, &opt_arg)) {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
COMMAND_ERROR("Unkown flag found:'--%s'\n", arg);
|
|
exit(EINVALIDARGS);
|
|
}
|
|
|
|
int command_parse_args(command_t *self, int *argc, char * const **argv)
|
|
{
|
|
int ret = 0;
|
|
|
|
for (; self->argc; self->argc--, self->argv++) {
|
|
const char *arg_opt = self->argv[0];
|
|
if (arg_opt[0] != '-' || !arg_opt[1]) {
|
|
break;
|
|
}
|
|
|
|
// short option
|
|
if (arg_opt[1] != '-') {
|
|
arg_opt = arg_opt + 1;
|
|
ret = command_parse_short_arg(self, arg_opt);
|
|
if (!ret) {
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// --
|
|
if (!arg_opt[2]) {
|
|
self->argc--;
|
|
self->argv++;
|
|
break;
|
|
}
|
|
|
|
// long option
|
|
arg_opt = arg_opt + 2;
|
|
ret = command_parse_long_arg(self, arg_opt);
|
|
if (ret == 0) {
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
if (self->argc > 0) {
|
|
*argc = self->argc;
|
|
*argv = (char * const *)self->argv;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
int command_valid_socket_append_array(command_option_t *option, const char *arg)
|
|
{
|
|
int len;
|
|
char **pos = NULL;
|
|
|
|
if (option == NULL) {
|
|
return -1;
|
|
}
|
|
if (!util_validate_socket(arg)) {
|
|
COMMAND_ERROR("Invalid socket name : %s", arg);
|
|
return -1;
|
|
}
|
|
|
|
for (pos = *(char ***)(option->data), len = 0; pos != NULL && *pos != NULL; pos++, len++) {
|
|
if (strcmp(*pos, arg) == 0) {
|
|
break;
|
|
}
|
|
}
|
|
if (pos != NULL && *pos != NULL) {
|
|
return 0;
|
|
}
|
|
|
|
if (util_array_append(option->data, arg) != 0) {
|
|
ERROR("merge hosts config failed");
|
|
return -1;
|
|
}
|
|
len++;
|
|
if (len > MAX_HOSTS) {
|
|
COMMAND_ERROR("Too many hosts, the max number is %d", MAX_HOSTS);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int check_default_ulimit_input(const char *val)
|
|
{
|
|
int ret = 0;
|
|
if (val == NULL || strcmp(val, "") == 0) {
|
|
COMMAND_ERROR("ulimit argument can't be empty");
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
|
|
if (val[0] == '=' || val[strlen(val) - 1] == '=') {
|
|
COMMAND_ERROR("Invalid ulimit argument: \"%s\", delimiter '=' can't"
|
|
" be the first or the last character", val);
|
|
ret = -1;
|
|
}
|
|
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
static void get_default_ulimit_split_parts(const char *val, char ***parts, size_t *parts_len, char deli)
|
|
{
|
|
*parts = util_string_split_multi(val, deli);
|
|
if (*parts == NULL) {
|
|
ERROR("Out of memory");
|
|
return;
|
|
}
|
|
*parts_len = util_array_len((const char **)(*parts));
|
|
}
|
|
|
|
static int parse_soft_hard_default_ulimit(const char *val, char **limitvals, size_t limitvals_len, int64_t *soft,
|
|
int64_t *hard)
|
|
{
|
|
int ret = 0;
|
|
// parse soft
|
|
ret = util_safe_llong(limitvals[0], (long long *)soft);
|
|
if (ret < 0) {
|
|
COMMAND_ERROR("Invalid ulimit soft value: \"%s\", parse int64 failed: %s", val, strerror(-ret));
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
|
|
// parse hard if exists
|
|
if (limitvals_len > 1) {
|
|
ret = util_safe_llong(limitvals[1], (long long *)hard);
|
|
if (ret < 0) {
|
|
COMMAND_ERROR("Invalid ulimit hard value: \"%s\", parse int64 failed: %s", val, strerror(-ret));
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
|
|
if (*soft > *hard) {
|
|
COMMAND_ERROR("Ulimit soft limit must be less than or equal to hard limit: %lld > %lld",
|
|
(long long int)(*soft), (long long int)(*hard));
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
} else {
|
|
*hard = *soft; // default to soft in case no hard was set
|
|
}
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
int check_default_ulimit_type(const char *type)
|
|
{
|
|
int ret = 0;
|
|
char **tmptype = NULL;
|
|
char *ulimit_valid_type[] = {
|
|
// "as", // Disabled since this doesn't seem usable with the way Docker inits a container.
|
|
"core", "cpu", "data", "fsize", "locks", "memlock", "msgqueue", "nice",
|
|
"nofile", "nproc", "rss", "rtprio", "rttime", "sigpending", "stack", NULL
|
|
};
|
|
|
|
for (tmptype = ulimit_valid_type; *tmptype != NULL; tmptype++) {
|
|
if (strcmp(type, *tmptype) == 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (*tmptype == NULL) {
|
|
COMMAND_ERROR("Invalid ulimit type: %s", type);
|
|
ret = -1;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static host_config_ulimits_element *parse_default_ulimit(const char *val)
|
|
{
|
|
int ret = 0;
|
|
int64_t soft = 0;
|
|
int64_t hard = 0;
|
|
size_t parts_len = 0;
|
|
size_t limitvals_len = 0;
|
|
char **parts = NULL;
|
|
char **limitvals = NULL;
|
|
host_config_ulimits_element *ulimit = NULL;
|
|
|
|
ret = check_default_ulimit_input(val);
|
|
if (ret != 0) {
|
|
return NULL;
|
|
}
|
|
|
|
get_default_ulimit_split_parts(val, &parts, &parts_len, '=');
|
|
if (parts == NULL) {
|
|
ERROR("Out of memory");
|
|
return NULL;
|
|
} else if (parts_len != 2) {
|
|
COMMAND_ERROR("Invalid ulimit argument: %s", val);
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
|
|
ret = check_default_ulimit_type(parts[0]);
|
|
if (ret != 0) {
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
|
|
if (parts[1][0] == ':' || parts[1][strlen(parts[1]) - 1] == ':') {
|
|
COMMAND_ERROR("Invalid ulimit value: \"%s\", delimiter ':' can't be the first"
|
|
" or the last character", val);
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
|
|
// parse value
|
|
get_default_ulimit_split_parts(parts[1], &limitvals, &limitvals_len, ':');
|
|
if (limitvals == NULL) {
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
|
|
if (limitvals_len > 2) {
|
|
COMMAND_ERROR("Too many limit value arguments - %s, can only have up to two, `soft[:hard]`",
|
|
parts[1]);
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
|
|
ret = parse_soft_hard_default_ulimit(val, limitvals, limitvals_len, &soft, &hard);
|
|
if (ret < 0) {
|
|
goto out;
|
|
}
|
|
|
|
ulimit = util_common_calloc_s(sizeof(host_config_ulimits_element));
|
|
if (ulimit == NULL) {
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
ulimit->name = util_strdup_s(parts[0]);
|
|
ulimit->hard = hard;
|
|
ulimit->soft = soft;
|
|
|
|
out:
|
|
util_free_array(parts);
|
|
util_free_array(limitvals);
|
|
if (ret != 0) {
|
|
free_host_config_ulimits_element(ulimit);
|
|
ulimit = NULL;
|
|
}
|
|
|
|
return ulimit;
|
|
}
|
|
|
|
int command_default_ulimit_append(command_option_t *option, const char *arg)
|
|
{
|
|
int ret = 0;
|
|
size_t ulimit_len;
|
|
host_config_ulimits_element *tmp = NULL;
|
|
host_config_ulimits_element **pos = NULL;
|
|
|
|
if (option == NULL) {
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
|
|
tmp = parse_default_ulimit(arg);
|
|
if (tmp == NULL) {
|
|
ERROR("parse default ulimit from arg failed");
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
|
|
for (pos = *(host_config_ulimits_element ***)(option->data); pos != NULL && *pos != NULL; pos++) {
|
|
if (strcmp((*pos)->name, tmp->name) == 0) {
|
|
break;
|
|
}
|
|
}
|
|
if (pos != NULL && *pos != NULL) {
|
|
(*pos)->hard = tmp->hard;
|
|
(*pos)->soft = tmp->soft;
|
|
goto out;
|
|
}
|
|
|
|
ulimit_len = ulimit_array_len(*(host_config_ulimits_element ***)(option->data));
|
|
if (ulimit_array_append(option->data, tmp, ulimit_len) != 0) {
|
|
ERROR("default ulimit append failed");
|
|
ret = -1;
|
|
}
|
|
|
|
out:
|
|
free_host_config_ulimits_element(tmp);
|
|
return ret;
|
|
}
|
|
|
|
|
|
int command_append_array(command_option_t *option, const char *arg)
|
|
{
|
|
if (option == NULL) {
|
|
return -1;
|
|
}
|
|
char ***array = option->data;
|
|
return util_array_append(array, arg);
|
|
}
|
|
|
|
int command_convert_u16(command_option_t *option, const char *arg)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (option == NULL) {
|
|
return -1;
|
|
}
|
|
ret = util_safe_u16(arg, option->data);
|
|
if (ret != 0) {
|
|
COMMAND_ERROR("Invalid value \"%s\" for flag --%s: %s", arg, option->large, strerror(-ret));
|
|
return EINVALIDARGS;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int command_convert_llong(command_option_t *opt, const char *arg)
|
|
{
|
|
int ret;
|
|
|
|
if (opt == NULL) {
|
|
return -1;
|
|
}
|
|
ret = util_safe_llong(arg, opt->data);
|
|
if (ret != 0) {
|
|
COMMAND_ERROR("Invalid value \"%s\" for flag --%s: %s", arg, opt->large, strerror(-ret));
|
|
return EINVALIDARGS;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int command_convert_uint(command_option_t *opt, const char *arg)
|
|
{
|
|
int ret;
|
|
if (opt == NULL) {
|
|
return -1;
|
|
}
|
|
ret = util_safe_uint(arg, opt->data);
|
|
if (ret != 0) {
|
|
COMMAND_ERROR("Invalid value \"%s\" for flag --%s: %s", arg, opt->large, strerror(-ret));
|
|
return EINVALIDARGS;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int command_convert_int(command_option_t *option, const char *arg)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (option == NULL) {
|
|
return -1;
|
|
}
|
|
ret = util_safe_int(arg, option->data);
|
|
if (ret != 0) {
|
|
COMMAND_ERROR("Invalid value \"%s\" for flag --%s: %s", arg, option->large, strerror(-ret));
|
|
return EINVALIDARGS;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int command_convert_nanoseconds(command_option_t *option, const char *arg)
|
|
{
|
|
if (option == NULL) {
|
|
return -1;
|
|
}
|
|
if (util_parse_time_str_to_nanoseconds(arg, option->data)) {
|
|
COMMAND_ERROR("Invalid value \"%s\" for flag --%s", arg, option->large);
|
|
return EINVALIDARGS;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int command_convert_membytes(command_option_t *option, const char *arg)
|
|
{
|
|
if (option == NULL) {
|
|
return -1;
|
|
}
|
|
if (util_parse_byte_size_string(arg, option->data) || (*(int64_t *)(option->data)) < 0) {
|
|
COMMAND_ERROR("Invalid value \"%s\" for flag --%s", arg, option->large);
|
|
return EINVALIDARGS;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int command_convert_memswapbytes(command_option_t *option, const char *arg)
|
|
{
|
|
if (option == NULL) {
|
|
return -1;
|
|
}
|
|
if (strcmp(arg, "-1") == 0) {
|
|
*(int64_t *)(option->data) = -1;
|
|
return 0;
|
|
}
|
|
if (command_convert_membytes(option, arg)) {
|
|
return EINVALIDARGS;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
size_t ulimit_array_len(host_config_ulimits_element **default_ulimit)
|
|
{
|
|
size_t len = 0;
|
|
host_config_ulimits_element **pos = NULL;
|
|
|
|
for (pos = default_ulimit; pos != NULL && *pos != NULL; pos++) {
|
|
len++;
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
int ulimit_array_append(host_config_ulimits_element ***ulimit_array, const host_config_ulimits_element *element,
|
|
const size_t len)
|
|
{
|
|
int ret;
|
|
size_t old_size, new_size;
|
|
host_config_ulimits_element *new_element = NULL;
|
|
host_config_ulimits_element **new_ulimit_array = NULL;
|
|
|
|
|
|
if (ulimit_array == NULL || element == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
// let new len to len + 2 for element and null
|
|
if (len > SIZE_MAX / sizeof(host_config_ulimits_element *) - 2) {
|
|
ERROR("Too many ulimit elements!");
|
|
return -1;
|
|
}
|
|
|
|
new_size = (len + 2) * sizeof(host_config_ulimits_element *);
|
|
old_size = len * sizeof(host_config_ulimits_element *);
|
|
|
|
ret = mem_realloc((void **)(&new_ulimit_array), new_size, (void *)*ulimit_array, old_size);
|
|
if (ret != 0) {
|
|
ERROR("Failed to realloc memory for append ulimit");
|
|
return -1;
|
|
}
|
|
*ulimit_array = new_ulimit_array;
|
|
|
|
new_element = util_common_calloc_s(sizeof(host_config_ulimits_element));
|
|
if (new_element == NULL) {
|
|
ERROR("Out of memory");
|
|
free_default_ulimit(*ulimit_array);
|
|
*ulimit_array = NULL;
|
|
return -1;
|
|
}
|
|
|
|
new_element->name = util_strdup_s(element->name);
|
|
new_element->hard = element->hard;
|
|
new_element->soft = element->soft;
|
|
new_ulimit_array[len] = new_element;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void free_default_ulimit(host_config_ulimits_element **default_ulimit)
|
|
{
|
|
host_config_ulimits_element **p = NULL;
|
|
|
|
for (p = default_ulimit; p != NULL && *p != NULL; p++) {
|
|
free_host_config_ulimits_element(*p);
|
|
}
|
|
free(default_ulimit);
|
|
}
|
|
|
|
|