Initial commit
Signed-off-by: Robert Baldyga <robert.baldyga@intel.com>
This commit is contained in:
167
casadm/Makefile
Normal file
167
casadm/Makefile
Normal file
@@ -0,0 +1,167 @@
|
||||
#
|
||||
# Copyright(c) 2012-2019 Intel Corporation
|
||||
# SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
#
|
||||
|
||||
PWD:=$(shell pwd)
|
||||
MODULESDIR:=$(PWD)/../modules
|
||||
UTILS_DIR:=$(PWD)/../utils
|
||||
BINARY_PATH = /sbin
|
||||
|
||||
VERSION_FILE := $(MODULESDIR)/CAS_VERSION
|
||||
|
||||
#
|
||||
# Section below enables creating build with experimental features
|
||||
#
|
||||
ifeq ($(CAS_EXT_EXP),1)
|
||||
DEFINES = WI_AVAILABLE
|
||||
endif
|
||||
|
||||
#
|
||||
# Add defines for version
|
||||
#
|
||||
-include $(VERSION_FILE)
|
||||
DEFINES += CAS_VERSION_MAIN=$(CAS_VERSION_MAIN)
|
||||
DEFINES += CAS_VERSION_MAJOR=$(CAS_VERSION_MAJOR)
|
||||
DEFINES += CAS_VERSION_MINOR=$(CAS_VERSION_MINOR)
|
||||
DEFINES += CAS_BUILD_NO=\"$(CAS_BUILD_NO)\"
|
||||
|
||||
#
|
||||
# Additional git version
|
||||
#
|
||||
ifneq ($(strip $(CAS_BUILD_FLAG)),)
|
||||
DEFINES += CAS_BUILD_FLAG=\"$(CAS_BUILD_FLAG)\"
|
||||
endif
|
||||
|
||||
#
|
||||
# Include directories
|
||||
#
|
||||
INCLUDES = .
|
||||
INCLUDES += $(MODULESDIR)/include
|
||||
|
||||
OBJDIR = .obj/
|
||||
TARGET = casadm
|
||||
TARGETS = $(TARGET)
|
||||
|
||||
#
|
||||
# Source to be complied
|
||||
#
|
||||
|
||||
OBJS = cas_lib.o
|
||||
OBJS += cas_main.o
|
||||
OBJS += argp.o
|
||||
OBJS += statistics_view_csv.o
|
||||
OBJS += cas_lib_utils.o
|
||||
OBJS += statistics_model.o
|
||||
OBJS += table.o
|
||||
OBJS += psort.o
|
||||
OBJS += statistics_view_text.o
|
||||
OBJS += intvector.o
|
||||
OBJS += statistics_view.o
|
||||
OBJS += statistics_view_raw_csv.o
|
||||
OBJS += csvparse.o
|
||||
OBJS += extended_err_msg.o
|
||||
OBJS += upgrade.o
|
||||
OBJS += safeclib/memmove_s.o
|
||||
OBJS += safeclib/memcpy_s.o
|
||||
OBJS += safeclib/memset_s.o
|
||||
OBJS += safeclib/strncpy_s.o
|
||||
OBJS += safeclib/strtok_s.o
|
||||
OBJS += safeclib/safe_str_constraint.o
|
||||
OBJS += safeclib/ignore_handler_s.o
|
||||
OBJS += safeclib/safe_mem_constraint.o
|
||||
OBJS += safeclib/mem_primitives_lib.o
|
||||
OBJS += safeclib/strnlen_s.o
|
||||
|
||||
#
|
||||
# Flags for C compilation
|
||||
#
|
||||
CFLAGS = $(patsubst %,-I%,$(INCLUDES))
|
||||
CFLAGS += $(patsubst %,-D%,$(DEFINES))
|
||||
ifdef DEBUG
|
||||
CFLAGS += -O0 -g
|
||||
else
|
||||
CFLAGS += -O2 -D_FORTIFY_SOURCE=2
|
||||
endif
|
||||
CFLAGS += -Wall -z relro -z now -fstack-protector -fPIC -Wformat -Wformat-security -fno-strict-aliasing
|
||||
|
||||
#
|
||||
# Flags for linking
|
||||
#
|
||||
LDFLAGS = -z noexecstack -z relro -z now -pie -pthread
|
||||
#
|
||||
# Targets
|
||||
#
|
||||
|
||||
all: sync
|
||||
$(MAKE) build
|
||||
|
||||
build: $(VERSION_FILE) $(TARGETS)
|
||||
|
||||
sync:
|
||||
@cd $(MODULESDIR) && $(MAKE) sync
|
||||
|
||||
#
|
||||
# Include dependencies file
|
||||
#
|
||||
$(TARGET): $(TARGET).a
|
||||
@echo " LD " $@
|
||||
@$(CC) $(CFLAGS) $(LDFLAGS) -o $(TARGET) $<
|
||||
|
||||
$(TARGET).a: $(patsubst %,$(OBJDIR)%,$(OBJS))
|
||||
@echo " AR " $@
|
||||
@ar rcs $@ $^
|
||||
@echo " AR " libcas.a
|
||||
@cp -f $@ libcas.a
|
||||
@ar d libcas.a $(OBJDIR)argp.o $(OBJDIR)cas_main.c
|
||||
|
||||
#
|
||||
# Generic target for C file
|
||||
#
|
||||
$(OBJDIR)%.o: %.c
|
||||
@echo " CC " $<
|
||||
@mkdir -p $(dir $@)
|
||||
ifeq ($(strip $(CAS_VERSION_MAIN)),)
|
||||
$(error "No version file")
|
||||
endif
|
||||
@$(CC) -c $(CFLAGS) -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -o "$@" "$<"
|
||||
|
||||
$(VERSION_FILE):
|
||||
@echo " VERSION " $@
|
||||
@cd $(MODULESDIR) && ./CAS_VERSION_GEN
|
||||
|
||||
clean:
|
||||
@echo " CLEAN "
|
||||
@rm -f *.a $(TARGETS)
|
||||
@rm -f $(shell find -name \*.d) $(shell find -name \*.o)
|
||||
|
||||
distclean: clean
|
||||
@rm -f $(VERSION_FILE)
|
||||
|
||||
install:
|
||||
@echo "Installing casadm"
|
||||
@install -m 755 $(TARGET) $(BINARY_PATH)/$(TARGET)
|
||||
@install -m 644 $(UTILS_DIR)/$(TARGET).8 /usr/share/man/man8/$(TARGET).8
|
||||
|
||||
@install -m 755 -d /etc/opencas
|
||||
@install -m 644 $(UTILS_DIR)/opencas.conf /etc/opencas/opencas.conf
|
||||
@install -m 444 $(UTILS_DIR)/ioclass-config.csv /etc/opencas/ioclass-config.csv
|
||||
@install -m 444 $(UTILS_DIR)/ext3-config.csv /etc/opencas/ext3-config.csv
|
||||
@install -m 444 $(UTILS_DIR)/ext4-config.csv /etc/opencas/ext4-config.csv
|
||||
|
||||
@install -m 644 $(UTILS_DIR)/opencas.conf.5 /usr/share/man/man5/opencas.conf.5
|
||||
|
||||
uninstall:
|
||||
@echo "Uninstalling casadm"
|
||||
@rm $(BINARY_PATH)/$(TARGET)
|
||||
@rm /usr/share/man/man8/$(TARGET).8
|
||||
|
||||
@rm /etc/opencas/opencas.conf
|
||||
@rm /etc/opencas/ioclass-config.csv
|
||||
@rm /etc/opencas/ext3-config.csv
|
||||
@rm /etc/opencas/ext4-config.csv
|
||||
@rm -rf /etc/opencas
|
||||
|
||||
@rm /usr/share/man/man5/opencas.conf.5
|
||||
|
||||
.PHONY: clean distclean all sync build install uninstall
|
803
casadm/argp.c
Normal file
803
casadm/argp.c
Normal file
@@ -0,0 +1,803 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2019 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "argp.h"
|
||||
#include "cas_lib.h"
|
||||
#include "cas_lib_utils.h"
|
||||
#include <sys/timeb.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define PADDING " "
|
||||
#define MAX_OPT_HELP_LEN 30
|
||||
|
||||
extern cas_printf_t cas_printf;
|
||||
|
||||
static int is_su_requied(const cli_command* commands, int cmd)
|
||||
{
|
||||
return commands[cmd].flags & CLI_SU_REQUIRED;
|
||||
}
|
||||
|
||||
static int is_command_hidden(const cli_command* commands, int cmd)
|
||||
{
|
||||
return commands[cmd].flags & CLI_COMMAND_HIDDEN;
|
||||
}
|
||||
|
||||
static void print_short_usage(const app *app_values)
|
||||
{
|
||||
cas_printf(LOG_INFO, "Usage: %s %s\n", app_values->name, app_values->info);
|
||||
}
|
||||
|
||||
static void print_info(const app *app_values)
|
||||
{
|
||||
cas_printf(LOG_INFO, "Try `%s --help | -H' for more information.\n", app_values->name);
|
||||
}
|
||||
|
||||
char *get_short_name_string(const char short_name, char *buf)
|
||||
{
|
||||
if (short_name) {
|
||||
snprintf(buf, 3, "-%c", short_name);
|
||||
} else {
|
||||
buf[0] = 0;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
char *command_name_with_slash(char *buf, size_t buf_size, char short_name, char *long_name) {
|
||||
if (short_name) {
|
||||
snprintf(buf, buf_size, "-%c/--%s", short_name, long_name);
|
||||
} else {
|
||||
snprintf(buf, buf_size, "--%s", long_name);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
char *command_name_in_brackets(char *buf, size_t buf_size, char short_name, char *long_name) {
|
||||
if (short_name) {
|
||||
snprintf(buf, buf_size, "--%s (-%c)", long_name, short_name);
|
||||
} else {
|
||||
snprintf(buf, buf_size, "--%s", long_name);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
void print_options_usage(cli_option* options, const char *separator,
|
||||
int (*view)(cli_option* options, int flag), int flag)
|
||||
{
|
||||
int print_separator = 0;
|
||||
int i;
|
||||
|
||||
if (NULL == options) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; options[i].long_name != NULL; ++i) {
|
||||
if (0 == view(&options[i], flag)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (print_separator) {
|
||||
/* Separator */
|
||||
cas_printf(LOG_INFO, "%s", separator);
|
||||
}
|
||||
print_separator = 1;
|
||||
|
||||
/* Long option name */
|
||||
cas_printf(LOG_INFO, "--%s", options[i].long_name);
|
||||
|
||||
/* Parameter */
|
||||
if (options[i].arg != NULL) {
|
||||
cas_printf(LOG_INFO, " <%s>",
|
||||
options[i].arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void print_command_header(const app *app_values, const cli_command *cmd)
|
||||
{
|
||||
cas_printf(LOG_INFO, "%s%s\n\n", PADDING,
|
||||
cmd->long_desc != NULL ? cmd->long_desc : cmd->desc);
|
||||
}
|
||||
|
||||
void print_list_options(cli_option* options, int flag,
|
||||
int (*view)(cli_option* options, int flag))
|
||||
{
|
||||
char buffer[2048];
|
||||
|
||||
for (; options->long_name != NULL; options++) {
|
||||
char *desc = options->desc;
|
||||
char short_name[3];
|
||||
|
||||
if (0 == view(options, flag)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((options->flags & CLI_OPTION_RANGE_INT)
|
||||
|| (options->flags & CLI_OPTION_DEFAULT_INT)) {
|
||||
desc = buffer;
|
||||
|
||||
if ((options->flags & CLI_OPTION_RANGE_INT)
|
||||
&& (options->flags
|
||||
& CLI_OPTION_DEFAULT_INT)) {
|
||||
snprintf(buffer, sizeof(buffer), options->desc,
|
||||
options->min_value,
|
||||
options->max_value,
|
||||
options->default_value);
|
||||
} else if (options->flags & CLI_OPTION_DEFAULT_INT) {
|
||||
snprintf(buffer, sizeof(buffer), options->desc,
|
||||
options->default_value);
|
||||
} else if (options->flags & CLI_OPTION_RANGE_INT) {
|
||||
snprintf(buffer, sizeof(buffer), options->desc,
|
||||
options->min_value,
|
||||
options->max_value);
|
||||
}
|
||||
}
|
||||
|
||||
get_short_name_string(options->short_name, short_name);
|
||||
if (options->arg != NULL) {
|
||||
char buf[MAX_OPT_HELP_LEN];
|
||||
if (options->flags & CLI_OPTION_OPTIONAL_ARG) {
|
||||
snprintf(buf, MAX_OPT_HELP_LEN, "--%s [<%s>]",
|
||||
options->long_name, options->arg);
|
||||
} else {
|
||||
snprintf(buf, MAX_OPT_HELP_LEN, "--%s <%s>",
|
||||
options->long_name, options->arg);
|
||||
}
|
||||
|
||||
cas_printf(LOG_INFO, "%s%-4s%-32s%s\n", PADDING,
|
||||
short_name, buf, desc);
|
||||
} else {
|
||||
cas_printf(LOG_INFO, "%s%-4s--%-30s%s\n", PADDING,
|
||||
short_name, options->long_name, desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void print_options_help(cli_option *options)
|
||||
{
|
||||
char buffer[2048];
|
||||
int i;
|
||||
|
||||
for (i = 0; options[i].long_name != NULL; ++i) {
|
||||
char *desc = options[i].desc;
|
||||
char short_name[3];
|
||||
if (options[i].flags & CLI_OPTION_HIDDEN) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((options[i].flags & CLI_OPTION_RANGE_INT)
|
||||
|| (options[i].flags & CLI_OPTION_DEFAULT_INT) ) {
|
||||
desc = buffer;
|
||||
|
||||
if ((options[i].flags & CLI_OPTION_RANGE_INT)
|
||||
&& (options[i].flags & CLI_OPTION_DEFAULT_INT) ) {
|
||||
snprintf(buffer, sizeof(buffer), options[i].desc,
|
||||
options[i].min_value,
|
||||
options[i].max_value,
|
||||
options[i].default_value);
|
||||
} else if (options[i].flags & CLI_OPTION_DEFAULT_INT) {
|
||||
snprintf(buffer, sizeof(buffer), options[i].desc,
|
||||
options[i].default_value);
|
||||
} else if (options[i].flags & CLI_OPTION_RANGE_INT) {
|
||||
snprintf(buffer, sizeof(buffer), options[i].desc,
|
||||
options[i].min_value,
|
||||
options[i].max_value);
|
||||
}
|
||||
}
|
||||
get_short_name_string(options[i].short_name, short_name);
|
||||
if (options[i].arg != NULL) {
|
||||
char buf[MAX_OPT_HELP_LEN];
|
||||
if (options[i].flags & CLI_OPTION_OPTIONAL_ARG) {
|
||||
snprintf(buf, MAX_OPT_HELP_LEN, "--%s [<%s>]",
|
||||
options[i].long_name,
|
||||
options[i].arg);
|
||||
} else {
|
||||
snprintf(buf, MAX_OPT_HELP_LEN, "--%s <%s>",
|
||||
options[i].long_name,
|
||||
options[i].arg);
|
||||
}
|
||||
|
||||
cas_printf(LOG_INFO, "%s%-4s%-32s%s\n", PADDING,
|
||||
short_name, buf, desc);
|
||||
} else {
|
||||
cas_printf(LOG_INFO, "%s%-4s--%-30s%s\n", PADDING,
|
||||
short_name, options[i].long_name,
|
||||
desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void print_namespace_help(app *app_values, cli_command *cmd)
|
||||
{
|
||||
char command_name[MAX_STR_LEN];
|
||||
char option_name[MAX_STR_LEN];
|
||||
cli_namespace *ns = cmd->namespace;
|
||||
int i;
|
||||
|
||||
cas_printf(LOG_INFO, "Usage: %s --%s --%s <NAME>\n\n", app_values->name,
|
||||
cmd->name, ns->long_name);
|
||||
|
||||
print_command_header(app_values, cmd);
|
||||
|
||||
command_name_in_brackets(command_name, MAX_STR_LEN, cmd->short_name, cmd->name);
|
||||
command_name_in_brackets(option_name, MAX_STR_LEN, ns->short_name, ns->long_name);
|
||||
|
||||
|
||||
cas_printf(LOG_INFO, "Valid values of NAME are:\n");
|
||||
for (i = 0; ns->entries[i].name; ++i)
|
||||
cas_printf(LOG_INFO, "%s%s - %s\n", PADDING, ns->entries[i].name, ns->entries[i].desc);
|
||||
|
||||
cas_printf(LOG_INFO, "\n");
|
||||
|
||||
for (i = 0; ns->entries[i].name; ++i) {
|
||||
cas_printf(LOG_INFO, "Options that are valid with %s %s %s are:\n",
|
||||
command_name, option_name, ns->entries[i].name);
|
||||
print_options_help(ns->entries[i].options);
|
||||
if (ns->entries[i + 1].name)
|
||||
cas_printf(LOG_INFO, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void print_command_help(app *app_values, cli_command *cmd)
|
||||
{
|
||||
int all_mandatory = 1;
|
||||
int all_hidden = 1;
|
||||
int i;
|
||||
|
||||
if (cmd->help) {
|
||||
(cmd->help)(app_values, cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmd->namespace) {
|
||||
print_namespace_help(app_values, cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
cas_printf(LOG_INFO, "Usage: %s --%s", app_values->name, cmd->name);
|
||||
|
||||
if (cmd->options != NULL) {
|
||||
for (i = 0; cmd->options[i].long_name != NULL; ++i) {
|
||||
if (cmd->options[i].flags & CLI_OPTION_HIDDEN) {
|
||||
continue;
|
||||
}
|
||||
|
||||
all_hidden = 0;
|
||||
|
||||
if (cmd->options[i].flags & CLI_OPTION_REQUIRED) {
|
||||
cas_printf(LOG_INFO, " --%s", cmd->options[i].long_name);
|
||||
if (cmd->options[i].arg != NULL) {
|
||||
if (cmd->options[i].flags & CLI_OPTION_OPTIONAL_ARG) {
|
||||
cas_printf(LOG_INFO, " [<%s>]", cmd->options[i].arg);
|
||||
} else {
|
||||
cas_printf(LOG_INFO, " <%s>", cmd->options[i].arg);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
all_mandatory = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!all_mandatory) {
|
||||
cas_printf(LOG_INFO, " [option...]");
|
||||
}
|
||||
}
|
||||
cas_printf(LOG_INFO, "\n\n");
|
||||
|
||||
print_command_header(app_values, cmd);
|
||||
|
||||
if (cmd->options && !all_hidden) {
|
||||
char option_name[MAX_STR_LEN];
|
||||
command_name_in_brackets(option_name, MAX_STR_LEN, cmd->short_name, cmd->name);
|
||||
cas_printf(LOG_INFO, "Options that are valid with %s are:\n", option_name);
|
||||
print_options_help(cmd->options);
|
||||
}
|
||||
}
|
||||
|
||||
void print_help(const app *app_values, const cli_command *commands)
|
||||
{
|
||||
int i;
|
||||
|
||||
cas_printf(LOG_INFO, "%s\n\n", app_values->title);
|
||||
print_short_usage(app_values);
|
||||
cas_printf(LOG_INFO, "\nAvailable commands:\n");
|
||||
|
||||
for (i = 0;; ++i) {
|
||||
char short_name[3];
|
||||
|
||||
if (commands[i].name == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_command_hidden(commands, i))
|
||||
continue;
|
||||
|
||||
get_short_name_string(commands[i].short_name, short_name);
|
||||
|
||||
cas_printf(LOG_INFO, "%s%-4s--%-25s%s\n", PADDING, short_name,
|
||||
commands[i].name, commands[i].desc);
|
||||
}
|
||||
|
||||
cas_printf(LOG_INFO, "\nFor detailed help on the above commands use --help after the command.\n"
|
||||
"e.g.\n%s%s --%s --help\n",
|
||||
PADDING, app_values->name, commands[0].name);
|
||||
|
||||
if (app_values->man != NULL) {
|
||||
cas_printf(LOG_INFO,
|
||||
"For more information, please refer to manual, Admin Guide (man %s)\n"
|
||||
"or go to support page <http://www.intel.com/support/go/cas>.\n",
|
||||
app_values->man);
|
||||
} else {
|
||||
cas_printf(LOG_INFO,
|
||||
"For more information, please refer to manual, Admin Guide\n"
|
||||
"or go to support page <http://www.intel.com/support/go/cas>.\n");
|
||||
}
|
||||
}
|
||||
|
||||
static int args_is_unrecognized(const char *cmd)
|
||||
{
|
||||
if (strempty(cmd)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ('-' == cmd[0]) {
|
||||
char c = cmd[1];
|
||||
|
||||
/* Check if short option (command) is proper */
|
||||
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
|
||||
if ('\0' == cmd[2]) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ('-' == cmd[1]) {
|
||||
char c = cmd[2];
|
||||
/* Long option (command), check if it is valid */
|
||||
|
||||
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int args_is(const char *in, const char *arg, const char c)
|
||||
{
|
||||
if (strempty(in)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ('-' == in[0]) {
|
||||
if (0 != c && c == in[1]) {
|
||||
if ('\0' == in[2]) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ('-' == in[1]) {
|
||||
/* Long option */
|
||||
if (0 == strncmp(&(in[2]), arg, MAX_STR_LEN)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_help(const char* cmd)
|
||||
{
|
||||
return args_is(cmd, "help", 'H');
|
||||
}
|
||||
|
||||
static int get_help_position(int argc, const char **argv)
|
||||
{
|
||||
int i;
|
||||
for (i = 2; i < argc; i++) {
|
||||
if (is_help(argv[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int get_option(const cli_option *options, const char* opt)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; options[i].long_name; ++i) {
|
||||
if (args_is(opt, options[i].long_name, options[i].short_name)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* log command as it was entered in CLI
|
||||
*/
|
||||
void log_command(int argc, const char **argv, int result, long long int timespan)
|
||||
{
|
||||
const int def_cmd_buf_len = 100;
|
||||
int cmd_buf_len = def_cmd_buf_len;
|
||||
int cmd_len = 0;
|
||||
int i = 0;
|
||||
char *command = malloc(cmd_buf_len);
|
||||
|
||||
if (!command) {
|
||||
cas_printf(LOG_ERR, "Memory allocation failed for logging.");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0 ; i != argc ; ++i) {
|
||||
int tok_len = strnlen_s(argv[i], MAX_STR_LEN);
|
||||
/* if reconstructed command width is longer than current
|
||||
* cmd_buf_len (length of command buffer), than resize it
|
||||
* to make it twice as big.
|
||||
*/
|
||||
if (tok_len + 1 + cmd_len > cmd_buf_len) {
|
||||
cmd_buf_len = (tok_len + 1 + cmd_buf_len) * 2;
|
||||
char *tmp = realloc(command, cmd_buf_len);
|
||||
/* if reallocation failed, cancel logging */
|
||||
if (!tmp) {
|
||||
cas_printf(LOG_ERR,
|
||||
"Memory allocation failed for logging.");
|
||||
free(command);
|
||||
return;
|
||||
}
|
||||
command = tmp;
|
||||
}
|
||||
/* append additional token to a string */
|
||||
memcpy_s(command + cmd_len, cmd_buf_len - cmd_len,
|
||||
argv[i], tok_len);
|
||||
cmd_len += tok_len;
|
||||
/* either a space or a null terminator */
|
||||
command[cmd_len] = (i == argc - 1) ? 0 : ' ';
|
||||
cmd_len++;
|
||||
}
|
||||
|
||||
caslog(LOG_DEBUG, "Casadm invoked with: \"%s\". "
|
||||
"Exit status is %d (%s). Command took %lld.%02lld s.",
|
||||
command, result, result? "failure" : "success",
|
||||
timespan / 1000, (timespan % 1000) / 10);
|
||||
free(command);
|
||||
}
|
||||
|
||||
/**
|
||||
* run command. Additionally log its execution and report any errors if
|
||||
* they've happened
|
||||
*/
|
||||
int run_command(cli_command *commands, int cmd, int argc, const char **argv)
|
||||
{
|
||||
int result;
|
||||
const char *syslog_path = "/var/log/messages";
|
||||
/* time buffer and stat buffer after running command */
|
||||
struct timeb t0;
|
||||
FILE *messages_f;
|
||||
/* time buffer and stat buffer after running command */
|
||||
struct timeb t1;
|
||||
long long int timespan;
|
||||
|
||||
/* collect time */
|
||||
ftime(&t0);
|
||||
/* collect stat buffer for syslog */
|
||||
messages_f = fopen(syslog_path, "r");
|
||||
if (messages_f) {
|
||||
fseek(messages_f, 0, SEEK_END);
|
||||
/* if opening file failed, don't stop command execution.
|
||||
* - just omit checking for /var/log/messages at the end
|
||||
*/
|
||||
} else {
|
||||
/* ubuntu case*/
|
||||
syslog_path = "/var/log/syslog";
|
||||
messages_f = fopen(syslog_path, "r");
|
||||
if (messages_f) {
|
||||
fseek(messages_f, 0, SEEK_END);
|
||||
}
|
||||
}
|
||||
|
||||
/* execute CAS command */
|
||||
result = commands[cmd].handle();
|
||||
ftime(&t1);
|
||||
timespan = (1000 * (t1.time - t0.time) + t1.millitm - t0.millitm);
|
||||
|
||||
if (commands[cmd].short_name != 'V') {
|
||||
log_command(argc, argv, result, timespan);
|
||||
}
|
||||
|
||||
/* print extra warning message IF command ended with failure and
|
||||
* syslog contains something */
|
||||
if (FAILURE == result && messages_f) {
|
||||
char line_buf[MAX_STR_LEN];
|
||||
bool kernel_said = false; /* set to true if CAS kernel module
|
||||
* said anything during command
|
||||
* execution */
|
||||
while (fgets(line_buf, MAX_STR_LEN - 1, messages_f)) {
|
||||
line_buf[MAX_STR_LEN - 1] = 0;
|
||||
if (strstr(line_buf, "CAS") &&
|
||||
strstr(line_buf, "kernel")) {
|
||||
kernel_said = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (kernel_said) {
|
||||
fprintf(stderr, "Error occurred, "
|
||||
"please see syslog (%s) for details. \n",
|
||||
syslog_path);
|
||||
}
|
||||
}
|
||||
|
||||
if (messages_f) {
|
||||
fclose(messages_f);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int count_arg_params(const char **argv, int argc)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
if ('-' == argv[i][0] && 0 != argv[i][1]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
void configure_cli_commands(cli_command *commands)
|
||||
{
|
||||
cli_command *cmd = commands;
|
||||
int ret;
|
||||
|
||||
while(cmd->name) {
|
||||
if (cmd->configure) {
|
||||
ret = cmd->configure(cmd);
|
||||
if (ret < 0) {
|
||||
cmd->flags |= CLI_COMMAND_HIDDEN;
|
||||
}
|
||||
}
|
||||
cmd++;
|
||||
}
|
||||
}
|
||||
|
||||
int args_parse(app *app_values, cli_command *commands, int argc, const char **argv)
|
||||
{
|
||||
int i, j, k, status = SUCCESS;
|
||||
int args_count, args_offset;
|
||||
const char **args_list = NULL;
|
||||
const char* cmd_name = argv[1];
|
||||
cli_ns_entry *entry = NULL;
|
||||
cli_option *options;
|
||||
int cmd, first_opt;
|
||||
|
||||
if (argc < 2) {
|
||||
cas_printf(LOG_ERR, "No command given.\n");
|
||||
print_info(app_values);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
if (args_is_unrecognized(cmd_name)) {
|
||||
cas_printf(LOG_ERR, "Unrecognized command %s\n", cmd_name);
|
||||
print_info(app_values);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
for (i = 0;; ++i) {
|
||||
if (commands[i].name == NULL) {
|
||||
if (is_help(cmd_name)) {
|
||||
print_help(app_values, commands);
|
||||
return SUCCESS;
|
||||
} else {
|
||||
cas_printf(LOG_ERR, "Unrecognized command %s\n",
|
||||
cmd_name);
|
||||
print_info(app_values);
|
||||
}
|
||||
return FAILURE;
|
||||
} else if (args_is(cmd_name, commands[i].name, commands[i].short_name)) {
|
||||
cmd = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
configure_cli_commands(commands);
|
||||
|
||||
if (argc >= 3 && get_help_position(argc, argv) != -1) {
|
||||
if (!is_command_hidden(commands, i)) {
|
||||
print_command_help(app_values, &commands[i]);
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
if (is_su_requied(commands, cmd)) {
|
||||
if (getuid() != 0) {
|
||||
cas_printf(LOG_ERR, "Must be run as root.\n");
|
||||
return FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (commands[cmd].options) {
|
||||
options = commands[cmd].options;
|
||||
first_opt = 2;
|
||||
} else if (commands[cmd].namespace) {
|
||||
if (argc < 3) {
|
||||
cas_printf(LOG_ERR, "Missing namespace option.\n");
|
||||
print_info(app_values);
|
||||
return FAILURE;
|
||||
}
|
||||
if (argc < 4) {
|
||||
cas_printf(LOG_ERR, "Missing namespace name.\n");
|
||||
print_info(app_values);
|
||||
return FAILURE;
|
||||
}
|
||||
if (!args_is(argv[2], commands[cmd].namespace->long_name,
|
||||
commands[cmd].namespace->short_name)) {
|
||||
cas_printf(LOG_ERR, "Unrecognized option.\n");
|
||||
print_info(app_values);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
entry = commands[cmd].namespace->entries;
|
||||
while (true) {
|
||||
if (!strcmp(argv[3], entry->name))
|
||||
break;
|
||||
if (!(++entry)->name) {
|
||||
cas_printf(LOG_ERR, "Unrecognized namespace entry.\n");
|
||||
print_info(app_values);
|
||||
return FAILURE;
|
||||
}
|
||||
}
|
||||
options = entry->options;
|
||||
first_opt = 4;
|
||||
} else {
|
||||
return run_command(commands, cmd, argc, argv);
|
||||
}
|
||||
|
||||
/* for each possible option:
|
||||
* - if it is required, check if it is supplied exactly once
|
||||
* - if it is not required, check if it is supplied at most once
|
||||
*/
|
||||
for (i = 0; options[i].long_name; ++i) {
|
||||
char option_name[MAX_STR_LEN];
|
||||
|
||||
/* count occurrences of an option (k as counter) */
|
||||
k = 0;
|
||||
for (j = first_opt; j < argc; ++j) {
|
||||
if (args_is(argv[j], options[i].long_name,
|
||||
options[i].short_name)) {
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
command_name_with_slash(option_name, MAX_STR_LEN,
|
||||
options[i].short_name, options[i].long_name);
|
||||
|
||||
if (options[i].flags & CLI_OPTION_REQUIRED) {
|
||||
if (!k) {
|
||||
cas_printf(LOG_ERR, "Missing required option %s\n", option_name);
|
||||
print_info(app_values);
|
||||
return FAILURE;
|
||||
}
|
||||
}
|
||||
if (k > 1) {
|
||||
cas_printf(LOG_ERR, "Option supplied more than once %s\n", option_name);
|
||||
print_info(app_values);
|
||||
return FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Store parameters for arguments. Terminate each list with NULL element.
|
||||
* Accomodate for max no of parameters */
|
||||
args_list = malloc(sizeof(*args_list) * (argc + 1));
|
||||
|
||||
if (args_list == NULL) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
/* iterate over all arguments that were actually passed to the CLI */
|
||||
args_count = args_offset = 0;
|
||||
for (i = first_opt; i < argc; ++i) {
|
||||
int opt;
|
||||
|
||||
if (args_is_unrecognized(argv[i])) {
|
||||
cas_printf(LOG_ERR, "Invalid format %s\n",
|
||||
argv[i]);
|
||||
print_info(app_values);
|
||||
|
||||
status = FAILURE;
|
||||
goto free_args;
|
||||
}
|
||||
|
||||
opt = get_option(options, argv[i]);
|
||||
if (opt == -1) {
|
||||
cas_printf(LOG_ERR, "Unrecognized option %s\n",
|
||||
argv[i]);
|
||||
print_info(app_values);
|
||||
|
||||
status = FAILURE;
|
||||
goto free_args;
|
||||
}
|
||||
|
||||
if (options[opt].arg != NULL) {
|
||||
|
||||
/* Count params for current argument. */
|
||||
args_count = count_arg_params(&argv[i + 1], argc - i - 1);
|
||||
|
||||
if (args_count == 0 && !(options[opt].flags & CLI_OPTION_OPTIONAL_ARG)) {
|
||||
|
||||
cas_printf(LOG_ERR, "Missing required argument in %s\n",
|
||||
argv[i]);
|
||||
print_info(app_values);
|
||||
|
||||
status = FAILURE;
|
||||
goto free_args;
|
||||
}
|
||||
|
||||
if (-1 != options[opt].args_count &&
|
||||
args_count != options[opt].args_count &&
|
||||
(0 != args_count || !(options[opt].flags & CLI_OPTION_OPTIONAL_ARG))) {
|
||||
|
||||
cas_printf(LOG_ERR, "Invalid number of arguments for %s\n",
|
||||
argv[i]);
|
||||
print_info(app_values);
|
||||
|
||||
status = FAILURE;
|
||||
goto free_args;
|
||||
}
|
||||
|
||||
/* Add params for current argument.
|
||||
* Terminate list with NULL element.*/
|
||||
for (k = args_offset, j = 0; j < args_count; j++) {
|
||||
args_list[k++] = argv[j + i + 1];
|
||||
}
|
||||
args_list[args_offset + args_count] = NULL;
|
||||
|
||||
i += args_count;
|
||||
}
|
||||
|
||||
if (commands[cmd].command_handle_opts) {
|
||||
status = commands[cmd].command_handle_opts(
|
||||
options[opt].long_name,
|
||||
&args_list[args_offset]);
|
||||
} else if (commands[cmd].namespace_handle_opts) {
|
||||
status = commands[cmd].namespace_handle_opts(
|
||||
entry->name,
|
||||
options[opt].long_name,
|
||||
&args_list[args_offset]);
|
||||
} else {
|
||||
cas_printf(LOG_ERR, "Internal error\n");
|
||||
status = FAILURE;
|
||||
goto free_args;
|
||||
}
|
||||
args_offset += args_count;
|
||||
|
||||
if (0 != status) {
|
||||
cas_printf(LOG_ERR, "Error during options handling\n");
|
||||
print_info(app_values);
|
||||
|
||||
status = FAILURE;
|
||||
goto free_args;
|
||||
}
|
||||
}
|
||||
|
||||
status = run_command(commands, cmd, argc, argv);
|
||||
|
||||
free_args:
|
||||
if (NULL != args_list) {
|
||||
free(args_list);
|
||||
args_list = NULL;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
133
casadm/argp.h
Normal file
133
casadm/argp.h
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2019 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#ifndef _ARGP_H
|
||||
#define _ARGP_H
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
enum CLI_OPTION_FLAGS {
|
||||
CLI_OPTION_REQUIRED = 1 << 0,
|
||||
CLI_OPTION_HIDDEN = 1 << 1,
|
||||
CLI_OPTION_RANGE_INT = 1 << 2, /*! if option has a min/max value */
|
||||
CLI_OPTION_DEFAULT_INT = 1 << 3, /*! if option has a default value */
|
||||
CLI_OPTION_OPTIONAL_ARG = 1 << 4 /*! if option argument is optional */
|
||||
};
|
||||
|
||||
enum CLI_COMMAND_FLAGS {
|
||||
CLI_SU_REQUIRED = 1 << 0,
|
||||
CLI_COMMAND_HIDDEN = 1 << 1
|
||||
};
|
||||
|
||||
#define ERROR -1
|
||||
#define SUCCESS 0
|
||||
#define FAILURE 1
|
||||
|
||||
/**
|
||||
* structure repsesenting each single option for CLI command (i.e. -i, -j for -R)
|
||||
*/
|
||||
typedef struct {
|
||||
char short_name; /*!< short option name, one-letter. i.e. 'i' representing -i
|
||||
*!< as --cache-id */
|
||||
char* long_name; /*!< long option name (in above described case it would be
|
||||
*!< "cache-id" */
|
||||
char* desc; /*!< description of an option (longer text...
|
||||
*!< may contain single %d for default value and/or pair of %d marks
|
||||
*!< for range of correct values. If it has both, default must come
|
||||
*!< after the range, so be careful about wording such messages) */
|
||||
int args_count; /*!< number of arguments (0 - no arguments, -1 - unspecified) */
|
||||
char* arg; /*!< type of an argument, descriptive. i.e. "NUM", "NAME" */
|
||||
int flags; /*!< as per CLI_OPTION_FLAGS */
|
||||
int min_value; /*!< min parameter value. (optional) */
|
||||
int max_value; /*!< max parameter value. (optional) */
|
||||
int default_value; /*!< default parameter value. (optional) */
|
||||
int priv; /*!< Private filed for command handler */
|
||||
} cli_option;
|
||||
|
||||
/*
|
||||
* In namespace entries options array is nested in another flexible array
|
||||
* (array of entries), so it cannot be flexible array itself. Because of that
|
||||
* we make it static array of options with reasonable lenght.
|
||||
*/
|
||||
#define MAX_OPTIONS 32
|
||||
|
||||
typedef struct {
|
||||
char* name; /*!< namespace entry name */
|
||||
char* desc; /*!< description of an namespace entry */
|
||||
cli_option options[MAX_OPTIONS];
|
||||
/*!< pointer to first element in null-terminated array of cli_option */
|
||||
} cli_ns_entry;
|
||||
|
||||
typedef struct {
|
||||
char short_name; /*!< short name of namespace */
|
||||
char* long_name; /*!< long name of namespace */
|
||||
cli_ns_entry entries[]; /*!< null-terminated array of namespace entries */
|
||||
} cli_namespace;
|
||||
|
||||
typedef struct {
|
||||
const char* name;
|
||||
char* info;
|
||||
char* title;
|
||||
char* doc;
|
||||
char* man;
|
||||
int block;
|
||||
} app;
|
||||
|
||||
struct _cli_command;
|
||||
typedef struct _cli_command cli_command;
|
||||
|
||||
/**
|
||||
* structure representing each CLI command, i.e. -S, -T...
|
||||
*/
|
||||
struct _cli_command {
|
||||
char* name; /*!< name of command (i.e. "start-cache" for --start-cache) */
|
||||
|
||||
char short_name; /*!< short name of command (i.e. "S" for -S/--start-cache) */
|
||||
|
||||
char* desc; /*!< description that appears with "casadm -H" invocation */
|
||||
|
||||
char* long_desc; /*!< option descripotion that appears with "casadm -O -H invocation */
|
||||
|
||||
cli_option* options; /*!< pointer to first element in null-terminated array of cli_option */
|
||||
|
||||
int (*command_handle_opts)(char*, const char**);
|
||||
/*! function pointer to function that processes options to command */
|
||||
|
||||
cli_namespace* namespace;
|
||||
/*! namespace description */
|
||||
|
||||
int (*namespace_handle_opts)(char*, char*, const char**);
|
||||
/*! function pointer to function that processes options to namespace */
|
||||
|
||||
int (*handle)(void); /*! function pointer to function that executes a command */
|
||||
|
||||
int flags; /*! command flags, as per CLI_COMMAND_FLAGS */
|
||||
|
||||
void (*help)(app *app_values, cli_command *cmd);
|
||||
/*! Custom help provider */
|
||||
int (*configure)(cli_command *cmd);
|
||||
/*! function pointer to function that configures command */
|
||||
};
|
||||
|
||||
char *command_name_in_brackets(char *buf, size_t buf_size, char short_name, char *long_name);
|
||||
|
||||
void print_help(const app *app_values, const cli_command *commands);
|
||||
|
||||
void print_options_usage(cli_option* options, const char *separator,
|
||||
int (*view)(cli_option* options, int flag), int flag);
|
||||
|
||||
void print_list_options(cli_option* options, int flag,
|
||||
int (*view)(cli_option* options, int flag));
|
||||
|
||||
void print_command_header(const app *app_values, const cli_command *cmd);
|
||||
|
||||
void configure_cli_commands(cli_command *commands);
|
||||
|
||||
int args_parse(app *app_values, cli_command *commands, int argc, const char **argv);
|
||||
|
||||
#endif
|
2860
casadm/cas_lib.c
Normal file
2860
casadm/cas_lib.c
Normal file
File diff suppressed because it is too large
Load Diff
297
casadm/cas_lib.h
Normal file
297
casadm/cas_lib.h
Normal file
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2019 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#ifndef __CAS_LIB_H__
|
||||
#define __CAS_LIB_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <syslog.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdarg.h>
|
||||
#include "safeclib/safe_str_lib.h"
|
||||
#include <cas_ioctl_codes.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
#define CTRL_DEV_PATH "/dev/cas_ctrl"
|
||||
|
||||
#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
|
||||
|
||||
#define FAILURE 1 /**< default non-zero exit code. */
|
||||
#define INTERRUPTED 2 /**< if command is interrupted */
|
||||
#define SUCCESS 0 /**< 0 exit code from majority of our functions
|
||||
stands for success */
|
||||
|
||||
struct core_device {
|
||||
int id;
|
||||
int cache_id;
|
||||
char path[MAX_STR_LEN];
|
||||
struct kcas_core_info info;
|
||||
};
|
||||
|
||||
struct cache_device {
|
||||
int id;
|
||||
int state;
|
||||
int expected_core_count;
|
||||
char device[MAX_STR_LEN];
|
||||
int mode;
|
||||
int eviction_policy;
|
||||
int cleaning_policy;
|
||||
int dirty;
|
||||
int flushed;
|
||||
unsigned size;
|
||||
int core_count;
|
||||
struct core_device cores[];
|
||||
};
|
||||
|
||||
struct cas_param {
|
||||
char *name;
|
||||
char *unit;
|
||||
char **value_names;
|
||||
uint32_t (*transform_value)(uint32_t value);
|
||||
uint32_t value;
|
||||
bool select;
|
||||
};
|
||||
|
||||
enum output_format_t {
|
||||
OUTPUT_FORMAT_INVALID = 0,
|
||||
OUTPUT_FORMAT_TABLE = 1,
|
||||
OUTPUT_FORMAT_CSV = 2,
|
||||
OUTPUT_FORMAT_DEFAULT = OUTPUT_FORMAT_TABLE
|
||||
};
|
||||
|
||||
enum metadata_mode_t {
|
||||
METADATA_MODE_INVALID = 0,
|
||||
METADATA_MODE_NORMAL,
|
||||
METADATA_MODE_ATOMIC,
|
||||
METADATA_MODE_DEFAULT = METADATA_MODE_NORMAL,
|
||||
};
|
||||
|
||||
#define STATS_FILTER_INVALID 0
|
||||
#define STATS_FILTER_CONF (1 << 0)
|
||||
#define STATS_FILTER_USAGE (1 << 1)
|
||||
#define STATS_FILTER_REQ (1 << 2)
|
||||
#define STATS_FILTER_BLK (1 << 3)
|
||||
#define STATS_FILTER_ERR (1 << 4)
|
||||
#define STATS_FILTER_IOCLASS (1 << 5)
|
||||
#define STATS_FILTER_ALL (STATS_FILTER_CONF | \
|
||||
STATS_FILTER_USAGE | \
|
||||
STATS_FILTER_REQ | \
|
||||
STATS_FILTER_BLK | \
|
||||
STATS_FILTER_ERR)
|
||||
#define STATS_FILTER_DEFAULT STATS_FILTER_ALL
|
||||
|
||||
#define STATS_FILTER_COUNTERS (STATS_FILTER_REQ | STATS_FILTER_BLK | STATS_FILTER_ERR)
|
||||
|
||||
const char *eviction_policy_to_name(uint8_t policy);
|
||||
const char *cleaning_policy_to_name(uint8_t policy);
|
||||
const char *cache_mode_to_name(uint8_t cache_mode);
|
||||
const char *get_cache_state_name(int cache_state);
|
||||
const char *get_core_state_name(int core_state);
|
||||
const char *metadata_variant_to_name(uint8_t variant);
|
||||
const char *metadata_mode_to_name(uint8_t metadata_mode);
|
||||
const char *seq_cutoff_policy_to_name(uint8_t seq_cutoff_policy);
|
||||
|
||||
__attribute__((format(printf, 2, 3)))
|
||||
typedef int (*cas_printf_t)(int log_level, const char *format, ...);
|
||||
|
||||
extern cas_printf_t cas_printf;
|
||||
|
||||
__attribute__((format(printf, 2, 3)))
|
||||
int caslog(int log_level, const char *template, ...);
|
||||
|
||||
#define CAS_CLI_HELP_METADATA_VARIANTS \
|
||||
CAS_METADATA_VARIANT_MAX"|" \
|
||||
CAS_METADATA_VARIANT_MIX"|" \
|
||||
CAS_METADATA_VARIANT_MIN
|
||||
|
||||
/* for CLI commands arguments */
|
||||
#define YES 1
|
||||
#define NO 0
|
||||
#define UNDEFINED -1
|
||||
void metadata_memory_footprint(uint64_t size, float *footprint, const char **units);
|
||||
|
||||
int start_cache(ocf_cache_id_t cache_id, unsigned int cache_init,
|
||||
const char *cache_device, ocf_cache_mode_t cache_mode,
|
||||
ocf_eviction_t eviction_policy_type,
|
||||
ocf_cache_line_size_t line_size, int force);
|
||||
int stop_cache(ocf_cache_id_t cache_id, int flush);
|
||||
|
||||
#ifdef WI_AVAILABLE
|
||||
#define CAS_CLI_HELP_START_CACHE_MODES "wt|wb|wa|pt|wi"
|
||||
#define CAS_CLI_HELP_SET_CACHE_MODES "wt|wb|wa|pt|wi"
|
||||
#define CAS_CLI_HELP_SET_CACHE_MODES_FULL "Write-Through, Write-Back, Write-Around, Pass-Through, Write-Invalidate"
|
||||
#define CAS_CLI_HELP_START_CACHE_MODES_FULL "Write-Through, Write-Back, Write-Around, Pass-Through, Write-Invalidate"
|
||||
#else
|
||||
#define CAS_CLI_HELP_START_CACHE_MODES "wt|wb|wa|pt"
|
||||
#define CAS_CLI_HELP_SET_CACHE_MODES "wt|wb|wa|pt"
|
||||
#define CAS_CLI_HELP_START_CACHE_MODES_FULL "Write-Through, Write-Back, Write-Around, Pass-Through"
|
||||
#define CAS_CLI_HELP_SET_CACHE_MODES_FULL "Write-Through, Write-Back, Write-Around, Pass-Through"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief handle set cache param command
|
||||
* @param cache_id id of cache device
|
||||
* @param params parameter array
|
||||
* @return exit code of successful completion is 0;
|
||||
* nonzero exit code means failure
|
||||
*/
|
||||
int cache_params_set(unsigned int cache_id, struct cas_param *params);
|
||||
|
||||
/**
|
||||
* @brief get cache param value
|
||||
* @param cache_id id of cache device
|
||||
* @param param_id id of cache parameter to retrive
|
||||
* @param param variable to pass value to caller
|
||||
* @return exit code of successful completion is 0;
|
||||
* nonzero exit code means failure
|
||||
*/
|
||||
int cache_get_param(unsigned int cache_id, unsigned int param_id,
|
||||
struct cas_param *param);
|
||||
/**
|
||||
* @brief handle get cache param command
|
||||
* @param cache_id id of cache device
|
||||
* @param params parameter array
|
||||
* @return exit code of successful completion is 0;
|
||||
* nonzero exit code means failure
|
||||
*/
|
||||
int cache_params_get(unsigned int cache_id, struct cas_param *params,
|
||||
unsigned int output_format);
|
||||
|
||||
/**
|
||||
* @brief handle set core param command
|
||||
* @param cache_id id of cache device
|
||||
* @param core_id id of core device
|
||||
* @param params parameter array
|
||||
* @return exit code of successful completion is 0;
|
||||
* nonzero exit code means failure
|
||||
*/
|
||||
int core_params_set(unsigned int cache_id, unsigned int core_id,
|
||||
struct cas_param *params);
|
||||
|
||||
/**
|
||||
* @brief handle get core param command
|
||||
* @param cache_id id of cache device
|
||||
* @param core_id id of core device
|
||||
* @param params parameter array
|
||||
* @return exit code of successful completion is 0;
|
||||
* nonzero exit code means failure
|
||||
*/
|
||||
int core_params_get(unsigned int cache_id, unsigned int core_id,
|
||||
struct cas_param *params, unsigned int output_format);
|
||||
|
||||
/**
|
||||
* @brief handle set cache mode (-Q) command
|
||||
* @param in cache mode identifier of cache mode (WRITE_BACK, WRITE_THROUGH etc...)
|
||||
* @param cache_id id of cache device
|
||||
* @param flush whenever we should flush cache during execution of command. Options: YES, NO, UNDEFINED.
|
||||
* (UNDEFINED is illegal when transitioning from Write-Back mode to any other mode)
|
||||
*/
|
||||
int set_cache_mode(unsigned int cache_state, unsigned int cache_id, int flush);
|
||||
|
||||
/**
|
||||
* @brief add core device to a cache
|
||||
*
|
||||
* @param cache_id cache to which new core is being added
|
||||
* @param core_device path to a core device that is being added
|
||||
* @param iogroup_id id of iogroup (this parameter is not exposed in user CLI)
|
||||
* @param try_add try add core to earlier loaded cache or add to core pool
|
||||
* @param update_path try update path to core device
|
||||
* @return 0 upon successful core addition, 1 upon failure
|
||||
*/
|
||||
int add_core(unsigned int cache_id, unsigned int core_id, const char *core_device, int try_add, int update_path);
|
||||
|
||||
int get_core_info(int fd, int cache_id, int core_id, struct kcas_core_info *info);
|
||||
|
||||
int remove_core(unsigned int cache_id, unsigned int core_id,
|
||||
bool detach, bool force_no_flush);
|
||||
|
||||
int core_pool_remove(const char *core_device);
|
||||
int get_core_pool_count(int fd);
|
||||
|
||||
int reset_counters(unsigned int cache_id, unsigned int core_id);
|
||||
|
||||
int flush_cache(unsigned int cache_id);
|
||||
int flush_core(unsigned int cache_id, unsigned int core_id);
|
||||
|
||||
int get_cas_capabilites_quiet(struct kcas_capabilites *caps);
|
||||
int get_cas_capabilites(struct kcas_capabilites *caps);
|
||||
|
||||
int nvme_format(const char *device_path, int metadata_mode, int force);
|
||||
|
||||
int check_cache_device(const char *device_path);
|
||||
|
||||
int partition_list(unsigned int cache_id, unsigned int output_format);
|
||||
int partition_setup(unsigned int cache_id, const char *file);
|
||||
int partition_is_name_valid(const char *name);
|
||||
|
||||
int cas_module_version(char *buff, int size);
|
||||
int disk_module_version(char *buff, int size);
|
||||
int list_caches(unsigned int list_format);
|
||||
int cache_status(unsigned int cache_id, unsigned int core_id, int io_class_id,
|
||||
unsigned int stats_filters, unsigned int stats_format);
|
||||
int get_inactive_core_count(const struct kcas_cache_info *cache_info);
|
||||
|
||||
int open_ctrl_device_quiet();
|
||||
int open_ctrl_device();
|
||||
int *get_cache_ids(int *cache_count);
|
||||
struct cache_device *get_cache_device_by_id_fd(int cache_id, int fd);
|
||||
struct cache_device **get_cache_devices(int *caches_count);
|
||||
void free_cache_devices_list(struct cache_device **caches, int caches_count);
|
||||
|
||||
int validate_dev(const char *dev_path);
|
||||
int validate_str_num(const char *source_str, const char *msg, long long int min, long long int max);
|
||||
int validate_str_num_sbd(const char *source_str, const char *msg, int min, int max);
|
||||
int validate_str_unum(const char *source_str, const char *msg, unsigned int min,
|
||||
unsigned int max);
|
||||
int validate_path(const char *path, int exist);
|
||||
|
||||
int validate_str_cache_mode(const char *s);
|
||||
int validate_str_ev_policy(const char *s);
|
||||
int validate_str_cln_policy(const char *s);
|
||||
int validate_str_meta_variant(const char *s);
|
||||
int validate_str_stats_filters(const char* s);
|
||||
int validate_str_output_format(const char* s);
|
||||
int validate_str_metadata_mode(const char* s);
|
||||
|
||||
/**
|
||||
* @brief calculate flush progress
|
||||
*
|
||||
* @param[in] dirty number of dirty blocks
|
||||
* @param[in] flush number of flushed blocks
|
||||
* @return flush progress or 0 if no flush is ongoing
|
||||
*/
|
||||
float calculate_flush_progress(unsigned dirty, unsigned flushed);
|
||||
|
||||
/**
|
||||
* @brief calculate flush progress of given cache
|
||||
*
|
||||
* @param[in] cache_id cache to which calculation applies
|
||||
* @param[out] progress flush progress
|
||||
* @return 0 on success, nonzero on failure
|
||||
*/
|
||||
int get_flush_progress(int unsigned cache_id, float *progress);
|
||||
|
||||
/**
|
||||
* @brief print error message corresponding with CAS extended error code.
|
||||
*/
|
||||
void print_err(int error_code);
|
||||
|
||||
/**
|
||||
* @brief get special device file path (/dev/sdX) for disk.
|
||||
*/
|
||||
int get_dev_path(const char* disk, char* buf, size_t num);
|
||||
|
||||
/**
|
||||
* @brief convert string to int
|
||||
*/
|
||||
bool str_to_int(const char* start, char** end, int *val);
|
||||
|
||||
#endif
|
535
casadm/cas_lib_utils.c
Normal file
535
casadm/cas_lib_utils.c
Normal file
@@ -0,0 +1,535 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2019 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <stdbool.h>
|
||||
#include "cas_lib.h"
|
||||
#include "extended_err_msg.h"
|
||||
#include "cas_lib_utils.h"
|
||||
#include "safeclib/safe_str_lib.h"
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <poll.h>
|
||||
#include <execinfo.h>
|
||||
extern cas_printf_t cas_printf;
|
||||
|
||||
#define IOCTL_RETRIES 3 /* this is how many times ioctl is called */
|
||||
|
||||
#define VT100_CLEARLINE "[K"
|
||||
#define ESCAPE 0x1b
|
||||
#define CARRIAGE_RETURN 0xd
|
||||
#define INVALID_DIRTY_NO ((uint64_t) (-1))
|
||||
|
||||
/* file descriptors for pipe */
|
||||
/* 1 is writing end, 0 is reading end of a pipe */
|
||||
int fdspipe[2];
|
||||
/* these must be global for handling signals */
|
||||
volatile static int interrupted = 0; /*!< signal was caught, interrupt the
|
||||
*!< management operation now! */
|
||||
static int finished = 0; /*!< if management operation has finished
|
||||
*!< (so that progressbar drawing thread
|
||||
*!< can either display "100%" or exit quietly */
|
||||
static int device_id = 0; /*!< id of caching device to which management
|
||||
*!< operation that is underway, applies */
|
||||
|
||||
|
||||
/**
|
||||
* Default signal handling function exists so that SIGINT wan't interrupt management
|
||||
* operations in unpredicted/disallowed way.
|
||||
*/
|
||||
void sig_handler_default(int x)
|
||||
{
|
||||
static int inter_counter = 0;
|
||||
inter_counter++;
|
||||
if (inter_counter>4) {
|
||||
cas_printf(LOG_ERR,
|
||||
"Can't interrupt CAS management process\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If management operation was interrupted due to user action (SIGINT)
|
||||
*/
|
||||
int was_ioctl_interrupted()
|
||||
{
|
||||
return interrupted;
|
||||
}
|
||||
|
||||
void sig_handler_interrupt_flushing(int x)
|
||||
{
|
||||
struct kcas_interrupt_flushing cmd_info;
|
||||
int fd = open(CTRL_DEV_PATH, 0);
|
||||
close(fdspipe[1]);
|
||||
interrupted = 1;
|
||||
|
||||
if (fd < 0) {
|
||||
cas_printf(LOG_ERR, "Device " CTRL_DEV_PATH " not found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&cmd_info, 0, sizeof(cmd_info));
|
||||
cmd_info.cache_id = device_id;
|
||||
|
||||
int res =
|
||||
run_ioctl(fd, KCAS_IOCTL_INTERRUPT_FLUSHING, &cmd_info);
|
||||
|
||||
close(fd);
|
||||
if (!res) {
|
||||
set_default_sig_handler();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* print current backtrace
|
||||
*/
|
||||
void dump_stack()
|
||||
{
|
||||
const int sym_max = 512;
|
||||
void *sym_buf[sym_max];
|
||||
int nsym;
|
||||
nsym = backtrace(sym_buf, sym_max);
|
||||
backtrace_symbols_fd(sym_buf, nsym, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sad CAS :(
|
||||
* dump stack to allow debugging.
|
||||
*/
|
||||
void segv_handler_default(int i)
|
||||
{
|
||||
cas_printf(LOG_ERR, "Segmentation fault\n");
|
||||
dump_stack();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/**
|
||||
* register default signal handling function
|
||||
*/
|
||||
void set_default_sig_handler()
|
||||
{
|
||||
signal(SIGINT, sig_handler_default);
|
||||
signal(SIGSEGV, segv_handler_default);
|
||||
}
|
||||
|
||||
/**
|
||||
* handle errors of cafe c library (wrong parameters passed)
|
||||
*/
|
||||
static void safe_lib_constraint_handler(const char *msg, void *ptr, errno_t error)
|
||||
{
|
||||
cas_printf(LOG_ERR, "Safe C lib error\n");
|
||||
if (msg) {
|
||||
cas_printf(LOG_ERR, "%s (%d)\n", msg, error);
|
||||
}
|
||||
dump_stack();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register constraint handler for safe_string_library
|
||||
*/
|
||||
void set_safe_lib_constraint_handler()
|
||||
{
|
||||
set_mem_constraint_handler_s(safe_lib_constraint_handler);
|
||||
set_str_constraint_handler_s(safe_lib_constraint_handler);
|
||||
}
|
||||
|
||||
int _open_ctrl_device(int quiet)
|
||||
{
|
||||
int fd;
|
||||
fd = open(CTRL_DEV_PATH, 0);
|
||||
|
||||
if (fd < 0) {
|
||||
if (!quiet) {
|
||||
cas_printf(LOG_ERR, "Device " CTRL_DEV_PATH
|
||||
" not found\n");
|
||||
cas_printf(LOG_INFO, "Is the kernel module loaded?\n");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int open_ctrl_device_quiet()
|
||||
{
|
||||
return _open_ctrl_device(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* calls open on control device; returns either error (-1) or a valid file descriptor
|
||||
*/
|
||||
int open_ctrl_device()
|
||||
{
|
||||
return _open_ctrl_device(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief print spinning wheel
|
||||
*/
|
||||
void print_progress_indicator(float prog, struct progress_status *ps)
|
||||
{
|
||||
static const char prog_indicator[] = { '|', '/', '-', '\\', '|', '/', '-', '\\'};
|
||||
/*!< set of characters implementing "spinning wheel" progress indicator */
|
||||
static int max_i = ARRAY_SIZE(prog_indicator);
|
||||
static int i = 0;
|
||||
|
||||
printf("%c%s... [%c]%c" VT100_CLEARLINE,
|
||||
CARRIAGE_RETURN, ps->friendly_name, prog_indicator[i], ESCAPE);
|
||||
if (50 < prog) {
|
||||
/* we're almost there. Ignore all signals at this stage */
|
||||
set_default_sig_handler();
|
||||
}
|
||||
|
||||
i = (i + 1) % max_i;
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief print progress bar once
|
||||
* @param prog degree of progress (0-100)
|
||||
* @param ps structure holding status between progressbar and caller
|
||||
*/
|
||||
void print_progress_bar(float prog, struct progress_status *ps)
|
||||
{
|
||||
/* constants affecting look of progressbar/activity indicator */
|
||||
static const char progress_full = '='; /*!< represents progress_step of progress */
|
||||
static const char progress_partial = '-';/*!< represents progress of more than 0
|
||||
*!< but less than progress_step */
|
||||
static const char progress_empty = ' '; /*!< progressbar didn't reach here */
|
||||
static const char delimiter_left = '['; /*!< left delimiter of progress bar */
|
||||
static const char delimiter_right = ']';/*!< right delimiter of progress bar */
|
||||
static const int progress_step = 2; /*!< progress step - percentage of progress to
|
||||
*!< be represented by one character. i.e. if
|
||||
*!< progress stepis set to 2, entire
|
||||
*!< progressbar is 50 chars wide+2 chars for
|
||||
*!< delimiters */
|
||||
|
||||
int i, remaining_m;
|
||||
time_t elapsed, remaining_s;
|
||||
|
||||
printf("%c%s... ", CARRIAGE_RETURN, ps->friendly_name);
|
||||
/* carriage return and "name of op"*/
|
||||
putchar(delimiter_left);
|
||||
|
||||
/* make sure, progressbar always moves forward and never backward */
|
||||
if (prog < ps->progress_accumulated) {
|
||||
prog = ps->progress_accumulated;
|
||||
} else {
|
||||
ps->progress_accumulated = prog;
|
||||
}
|
||||
|
||||
/* print actual progress bar */
|
||||
for (i = progress_step; i <= prog; i += progress_step){
|
||||
putchar(progress_full);
|
||||
}
|
||||
|
||||
if (((int)prog) % progress_step) {
|
||||
putchar(progress_partial);
|
||||
i += progress_step;
|
||||
}
|
||||
|
||||
for (; i <= 100; i += progress_step){
|
||||
putchar(progress_empty);
|
||||
}
|
||||
|
||||
elapsed = time(NULL) - ps->time_started;
|
||||
|
||||
remaining_s = ((100 - prog) * elapsed) / (prog ?: 1);
|
||||
remaining_m = remaining_s / 60;
|
||||
remaining_s -= remaining_m * 60;
|
||||
|
||||
if (remaining_m) {
|
||||
/* ESCAPE VT100_CLEARLINE is terminal control sequence to clear "rest
|
||||
* of the line */
|
||||
printf("%c %3.1f%% [%dm%02lds remaining]%c" VT100_CLEARLINE,
|
||||
delimiter_right, prog, remaining_m, remaining_s, ESCAPE);
|
||||
} else {
|
||||
printf("%c %3.1f%% [%lds remaining]%c" VT100_CLEARLINE,
|
||||
delimiter_right, prog, remaining_s, ESCAPE);
|
||||
}
|
||||
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief either print a progressbar or spinning wheel depending on prog
|
||||
*/
|
||||
void print_progress_bar_or_indicator(float prog, struct progress_status *ps)
|
||||
{
|
||||
if (0.01 > prog || 99.99 < prog) {
|
||||
print_progress_indicator(prog, ps);
|
||||
} else {
|
||||
print_progress_bar(prog, ps);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* initialize progressbar structure;
|
||||
*/
|
||||
void init_progress_bar(struct progress_status *ps)
|
||||
{
|
||||
if (NULL != ps) {
|
||||
memset(ps, 0, sizeof(*ps));
|
||||
ps->dirty_clines_curr = INVALID_DIRTY_NO;
|
||||
ps->dirty_clines_initial = INVALID_DIRTY_NO;
|
||||
ps->time_started = time(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void get_core_flush_progress(int fd, int cache_id, int core_id, float *prog)
|
||||
{
|
||||
struct kcas_core_info cmd_info;
|
||||
|
||||
memset(&cmd_info, 0, sizeof(cmd_info));
|
||||
cmd_info.cache_id = cache_id;
|
||||
cmd_info.core_id = core_id;
|
||||
|
||||
if (0 == ioctl(fd, KCAS_IOCTL_CORE_INFO, &cmd_info)) {
|
||||
*prog = calculate_flush_progress(cmd_info.stats.dirty,
|
||||
cmd_info.stats.flushed);
|
||||
}
|
||||
}
|
||||
|
||||
void get_cache_flush_progress(int fd, int cache_id, float *prog)
|
||||
{
|
||||
struct kcas_cache_info cmd_info;
|
||||
|
||||
memset(&cmd_info, 0, sizeof(cmd_info));
|
||||
cmd_info.cache_id = cache_id;
|
||||
|
||||
if (0 == ioctl(fd, KCAS_IOCTL_CACHE_INFO, &cmd_info)) {
|
||||
*prog = calculate_flush_progress(cmd_info.info.dirty,
|
||||
cmd_info.info.flushed);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* pthread thread handling function - runs during proper ioctl execution. Prints command progress
|
||||
*/
|
||||
void *print_command_progress(void *th_arg)
|
||||
{
|
||||
static const int
|
||||
show_progressbar_after = 2; /*!< threshold in seconds */
|
||||
|
||||
int do_print_progress_bar = 0;
|
||||
int mseconds = 0; /*< milliseconds */
|
||||
int fd;
|
||||
float prog = 0.;
|
||||
struct progress_status *ps = th_arg;
|
||||
/* argument of command progress of which is monitored */
|
||||
/*1,2,0 are descriptors of stdout, err and in respectively*/
|
||||
int running_tty = isatty(1) && isatty(2) && isatty(0);
|
||||
struct sigaction new_action, old_action;
|
||||
|
||||
fd = open(CTRL_DEV_PATH, 0);
|
||||
if (fd < 0) {
|
||||
cas_printf(LOG_ERR, "Device " CTRL_DEV_PATH " not found\n");
|
||||
return NULL; /* FAILURE; */
|
||||
}
|
||||
|
||||
device_id = ps->cache_id;
|
||||
|
||||
sigaction(SIGINT, NULL, &old_action);
|
||||
if (old_action.sa_handler != SIG_IGN) {
|
||||
new_action.sa_handler = sig_handler_interrupt_flushing;
|
||||
sigemptyset(&new_action.sa_mask);
|
||||
new_action.sa_flags = 0;
|
||||
sigaction(SIGINT, &new_action, NULL);
|
||||
}
|
||||
|
||||
sched_yield();
|
||||
|
||||
while (1) {
|
||||
struct pollfd pfd;
|
||||
struct timespec ts;
|
||||
sigset_t sigmask;
|
||||
int ppoll_res;
|
||||
sigemptyset(&sigmask);
|
||||
ts.tv_sec = 1;
|
||||
ts.tv_nsec = 0;
|
||||
pfd.fd = fdspipe[0];
|
||||
pfd.events = POLLIN | POLLRDHUP;
|
||||
ppoll_res = ppoll(&pfd, 1, &ts, &sigmask);
|
||||
if (ppoll_res < 0) {
|
||||
if (ENOMEM == errno) {
|
||||
sleep(1);
|
||||
/* ppoll call failed due to insufficient memory */
|
||||
} else if (EINTR == errno) {
|
||||
interrupted = 1;
|
||||
} else { /* other error conditions are EFAULT or EINVAL
|
||||
* cannot happen in realistic conditions,
|
||||
* and are likely to refer to OS errors, which
|
||||
* cannot possibly be handled. Perform abortion.
|
||||
*/
|
||||
cas_printf(LOG_ERR, "Failed ppoll");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
mseconds += 1000;
|
||||
|
||||
if (interrupted) {
|
||||
/* if flushing is interrupted by signal, don't proceed with displaying
|
||||
* any kind of progress bar. if bar was previously printed,
|
||||
* print indicator instead */
|
||||
if (do_print_progress_bar) {
|
||||
print_progress_indicator(100, ps);
|
||||
}
|
||||
break;
|
||||
} else if (finished) {
|
||||
if (do_print_progress_bar) {
|
||||
print_progress_bar_or_indicator(100., ps);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (ps->core_id == OCF_CORE_ID_INVALID) {
|
||||
get_cache_flush_progress(fd, ps->cache_id, &prog);
|
||||
} else {
|
||||
get_core_flush_progress(fd, ps->cache_id, ps->core_id, &prog);
|
||||
}
|
||||
|
||||
/* it is normal that ioctl to get statistics
|
||||
* fails from time to time. Most common cases
|
||||
* of it are:
|
||||
* - during --start-cache when cache isn't added
|
||||
* - during --stopping-cache, when progress is
|
||||
* supposed to read "100%", but cache is actually
|
||||
* already removed and its stopping progress can't
|
||||
* be queried at all.
|
||||
*/
|
||||
if (mseconds >= show_progressbar_after * 1000
|
||||
&& running_tty && prog < 50) {
|
||||
do_print_progress_bar = 1;
|
||||
}
|
||||
|
||||
if (do_print_progress_bar) {
|
||||
print_progress_bar_or_indicator(prog, ps);
|
||||
}
|
||||
}
|
||||
close(fdspipe[0]);
|
||||
|
||||
close(fd);
|
||||
|
||||
/* if progressbar was displayed at least one, clear line */
|
||||
if (do_print_progress_bar) {
|
||||
printf("%c%c" VT100_CLEARLINE, CARRIAGE_RETURN, ESCAPE);
|
||||
}
|
||||
fflush(stdout);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Run ioctl in a way that displays progressbar (if flushing operation takes longer)
|
||||
* Catch SIGINT signal.
|
||||
* @param friendly_name name of management operation that shall
|
||||
* be displayed in command prompt
|
||||
*/
|
||||
int run_ioctl_interruptible(int fd, int command, void *cmd,
|
||||
char *friendly_name, int cache_id, int core_id)
|
||||
{
|
||||
pthread_t thread;
|
||||
int ioctl_res;
|
||||
struct progress_status ps;
|
||||
sigset_t sigset;
|
||||
|
||||
init_progress_bar(&ps);
|
||||
ps.friendly_name = friendly_name;
|
||||
ps.cache_id = cache_id;
|
||||
ps.core_id = core_id;
|
||||
if (pipe(fdspipe)) {
|
||||
cas_printf(LOG_ERR,"Failed to allocate pipes.\n");
|
||||
return -1;
|
||||
}
|
||||
interrupted = 0;
|
||||
|
||||
sigemptyset(&sigset);
|
||||
sigaddset(&sigset, SIGINT);
|
||||
pthread_sigmask(SIG_BLOCK, &sigset, NULL);
|
||||
|
||||
pthread_create(&thread, 0, print_command_progress, &ps);
|
||||
ioctl_res = run_ioctl(fd, command, cmd);
|
||||
if (!interrupted) {
|
||||
close(fdspipe[1]);
|
||||
}
|
||||
finished = 1;
|
||||
|
||||
pthread_join(thread, 0);
|
||||
|
||||
return ioctl_res;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief ioctl wrapper that retries ioctl attempts within one second timeouts
|
||||
* @param[in] fd as for IOCTL(2)
|
||||
* @param[in] command as for IOCTL(2)
|
||||
* @param[inout] cmd_info as for IOCTL(2)
|
||||
*/
|
||||
int run_ioctl(int fd, int command, void *cmd)
|
||||
{
|
||||
int i, ret;
|
||||
struct timespec timeout = {
|
||||
.tv_sec = 1,
|
||||
.tv_nsec = 0,
|
||||
};
|
||||
|
||||
for (i = 0; i < IOCTL_RETRIES; i++) {
|
||||
ret = ioctl(fd, command, cmd);
|
||||
|
||||
if (ret < 0) {
|
||||
if (interrupted) {
|
||||
return -EINTR;
|
||||
} if (EINTR == errno) {
|
||||
return -EINTR;
|
||||
} else if (EBUSY == errno) {
|
||||
int nret = nanosleep(&timeout, NULL);
|
||||
if (nret) {
|
||||
return -EINTR;
|
||||
}
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int create_pipe_pair(FILE **intermediate_file)
|
||||
{
|
||||
/* 1 is writing end, 0 is reading end of a pipe */
|
||||
int pipefd[2];
|
||||
|
||||
if (pipe(pipefd)) {
|
||||
cas_printf(LOG_ERR,"Failed to create unidirectional pipe.\n");
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
intermediate_file[0] = fdopen(pipefd[0], "r");
|
||||
if (!intermediate_file[0]) {
|
||||
cas_printf(LOG_ERR,"Failed to open reading end of an unidirectional pipe.\n");
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
return FAILURE;
|
||||
}
|
||||
intermediate_file[1] = fdopen(pipefd[1], "w");
|
||||
if (!intermediate_file[1]) {
|
||||
cas_printf(LOG_ERR,"Failed to open reading end of an unidirectional pipe.\n");
|
||||
fclose(intermediate_file[0]);
|
||||
close(pipefd[1]);
|
||||
return FAILURE;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
68
casadm/cas_lib_utils.h
Normal file
68
casadm/cas_lib_utils.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2019 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#ifndef __CAS_LIB_UTILS_H__
|
||||
#define __CAS_LIB_UTILS_H__
|
||||
|
||||
struct progress_status {
|
||||
uint64_t
|
||||
dirty_clines_initial; /*!< amount of dirty clines when command is initiated */
|
||||
|
||||
uint64_t
|
||||
dirty_clines_curr; /*!< amount of dirty clines at current progress level */
|
||||
|
||||
int progress_accumulated; /*!< this is to ensure that progressbar is always
|
||||
*!< from 0 to 100% and progress indicated by it
|
||||
*!< never actually drops. */
|
||||
int time_started; /*!< time when particular long running
|
||||
*!< operation was started */
|
||||
char *friendly_name; /*!< name of management operation that shall
|
||||
*!< be displayed in command prompt */
|
||||
int cache_id; /*!< cache id */
|
||||
int core_id; /*!< core id */
|
||||
};
|
||||
|
||||
|
||||
void init_progress_bar(struct progress_status *ps);
|
||||
void print_progress_bar_or_indicator(float prog, struct progress_status *ps);
|
||||
int run_ioctl(int fd, int command, void *cmd);
|
||||
int run_ioctl_interruptible(int fd, int command, void *cmd,
|
||||
char *friendly_name, int cache_id, int core_id);
|
||||
int open_ctrl_device();
|
||||
int was_ioctl_interrupted();
|
||||
void set_default_sig_handler();
|
||||
void set_safe_lib_constraint_handler();
|
||||
|
||||
|
||||
/**
|
||||
* function creates pair files representing an unnamed pipe.
|
||||
* this is highlevel counterpart to pipe syscall.
|
||||
*
|
||||
* null is returned upon failure;
|
||||
*
|
||||
* FILE *pipes[2] is returned upon success.
|
||||
* 1 is writing end, 0 is reading end of a pipe
|
||||
*/
|
||||
int create_pipe_pair(FILE **);
|
||||
|
||||
/**
|
||||
* Check if string is empty
|
||||
*
|
||||
* @param str - reference to the string
|
||||
* @retval 1 string is empty
|
||||
* @retval 0 string is not empty
|
||||
*/
|
||||
static inline int strempty(const char *str)
|
||||
{
|
||||
if (NULL == str) {
|
||||
return 1;
|
||||
} else if ('\0' == str[0]) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
2024
casadm/cas_main.c
Normal file
2024
casadm/cas_main.c
Normal file
File diff suppressed because it is too large
Load Diff
483
casadm/csvparse.c
Normal file
483
casadm/csvparse.c
Normal file
@@ -0,0 +1,483 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2019 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdint.h>
|
||||
#include "csvparse.h"
|
||||
#include "cas_lib_utils.h"
|
||||
#include "safeclib/safe_lib.h"
|
||||
#include <cas_ioctl_codes.h>
|
||||
|
||||
#define SUCCESS 0
|
||||
#define FAILURE 1
|
||||
|
||||
struct CSVFILE_t {
|
||||
FILE *f; /**< underlying byte stream*/
|
||||
int num_columns; /**< number of columns in recently read
|
||||
line of CSV file */
|
||||
int alloc_column_ptrs; /**< number of pointers to columns
|
||||
that can be fit in columns buffer */
|
||||
char **columns; /**< buffer contains exactly one pointer to each
|
||||
column of a csv file */
|
||||
char *buffer; /**< buffer to which recently read line of a csv file
|
||||
is stored */
|
||||
int buffer_size; /**< size of a buffer */
|
||||
|
||||
char csv_comment; /**< character markng whole line comment. if set to null,
|
||||
comments in file are not respected */
|
||||
char csv_separator; /**< csv separator (by default coma, but in some csv formats
|
||||
it is something different */
|
||||
};
|
||||
|
||||
#define DEF_ALLOC_COL_PTRS 2
|
||||
#define DEF_CSV_FILE_BUFFER_SIZE 20
|
||||
|
||||
/* return error when input dataset size exceeds some common sense limitations */
|
||||
#define MAX_NUM_COLUMNS 100
|
||||
#define MAX_LINE_LENGTH 8192
|
||||
|
||||
CSVFILE *csv_open(const char *path, const char *mode)
|
||||
{
|
||||
CSVFILE *csv;
|
||||
|
||||
if (!path || !mode) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* open underlying file as a character stream */
|
||||
FILE *f = fopen(path, mode);
|
||||
if (!f) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
csv = csv_fopen(f);
|
||||
if (NULL == csv) {
|
||||
fclose(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return csv;
|
||||
}
|
||||
|
||||
CSVFILE *csv_fopen(FILE *f)
|
||||
{
|
||||
CSVFILE *cf = malloc(sizeof(*cf));
|
||||
if (!cf) {
|
||||
return NULL;
|
||||
}
|
||||
/* allocate storage for columns of CSV file */
|
||||
cf->num_columns = 0;
|
||||
cf->alloc_column_ptrs = DEF_ALLOC_COL_PTRS;
|
||||
|
||||
cf->columns = malloc(cf->alloc_column_ptrs * sizeof(char *));
|
||||
if (!cf->columns) {
|
||||
free(cf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* allocate storage for line of CSV file */
|
||||
cf->buffer_size = DEF_CSV_FILE_BUFFER_SIZE;
|
||||
cf->buffer = malloc(cf->buffer_size);
|
||||
if (!cf->buffer) {
|
||||
free(cf->columns);
|
||||
free(cf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* assign underlying file as a character stream */
|
||||
cf->f = f;
|
||||
|
||||
cf->csv_separator = ',';
|
||||
cf->csv_comment = 0;
|
||||
|
||||
return cf;
|
||||
}
|
||||
|
||||
void csv_close(CSVFILE *cf)
|
||||
{
|
||||
fclose(cf->f);
|
||||
csv_close_nu(cf);
|
||||
}
|
||||
|
||||
void csv_close_nu(CSVFILE *cf)
|
||||
{
|
||||
free(cf->columns);
|
||||
free(cf->buffer);
|
||||
memset(cf, 0, sizeof(*cf));
|
||||
free(cf);
|
||||
}
|
||||
|
||||
/**
|
||||
* internal helper function for the library.
|
||||
*/
|
||||
static int ensure_items_array(CSVFILE *cf)
|
||||
{
|
||||
if (cf->num_columns > MAX_NUM_COLUMNS) {
|
||||
return FAILURE;
|
||||
} else if (cf->num_columns < cf->alloc_column_ptrs) {
|
||||
return SUCCESS;
|
||||
} else {
|
||||
char **tmp;
|
||||
cf->alloc_column_ptrs = cf->num_columns * 2;
|
||||
tmp =
|
||||
realloc(cf->columns,
|
||||
cf->alloc_column_ptrs * sizeof(char *));
|
||||
if (!tmp) {
|
||||
return FAILURE;
|
||||
} else {
|
||||
cf->columns = tmp;
|
||||
return SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function checks if CSV file is a valid one.
|
||||
*/
|
||||
bool csv_is_valid(CSVFILE *cf)
|
||||
{
|
||||
if (!cf) {
|
||||
return false;
|
||||
} else if (!cf->f) {
|
||||
return false;
|
||||
} else if (!cf->columns) {
|
||||
return false;
|
||||
} else if (!cf->buffer) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static int csv_read_line(CSVFILE *cf)
|
||||
{
|
||||
char *line;
|
||||
char *c;
|
||||
int i, len;
|
||||
int already_read = 0;
|
||||
/* fgets reads at most buffer_size-1 characters and always places NULL
|
||||
* at the end. */
|
||||
|
||||
while (true) {
|
||||
line = fgets(cf->buffer + already_read,
|
||||
cf->buffer_size - already_read, cf->f);
|
||||
if (!line) {
|
||||
return FAILURE;
|
||||
}
|
||||
line = cf->buffer;
|
||||
/* check that entire line was read; if failed, expand buffer and retry
|
||||
* or (in case of eof) be happy with what we have */
|
||||
c = line;
|
||||
i = 0;
|
||||
|
||||
while (*c && *c != '\n') {
|
||||
c++;
|
||||
i++;
|
||||
}
|
||||
len = i;
|
||||
if (len > MAX_LINE_LENGTH) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
/* buffer ends with 0 while it is not an EOF - sign that we have NOT read entire line
|
||||
* - try to expand buffer*/
|
||||
if (!*c && !feof(cf->f)) {
|
||||
already_read = cf->buffer_size - 1;
|
||||
cf->buffer_size *= 2;
|
||||
char *tmp = realloc(cf->buffer, cf->buffer_size);
|
||||
|
||||
if (tmp) {
|
||||
cf->buffer = tmp;
|
||||
continue;
|
||||
} else {
|
||||
return FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (cf->buffer[i] == '\n') {
|
||||
cf->buffer[i] = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int csv_read(CSVFILE *cf)
|
||||
{
|
||||
int i, j, spaces_at_end;
|
||||
bool parsing_token = false; /* if false, "cursor" is over whitespace, otherwise
|
||||
* it is over part of token */
|
||||
|
||||
bool quotation = false;
|
||||
if (!csv_is_valid(cf)) {
|
||||
return FAILURE;
|
||||
}
|
||||
if (csv_read_line(cf)) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
cf->num_columns = 0;
|
||||
cf->columns[0] = 0;
|
||||
spaces_at_end = 0;
|
||||
|
||||
while (cf->buffer[i]) {
|
||||
if (quotation) { /* handling text within quotation marks -
|
||||
* ignore commas in this kind of text and don't strip spaces */
|
||||
if (cf->buffer[i] == '"' && cf->buffer[i + 1] == '"') {
|
||||
/* double quotation mark is considered escaped quotation by
|
||||
* Micros~1 Excel. We should do likewise */
|
||||
if (!parsing_token) { /* start of an cf->buffer */
|
||||
cf->columns[cf->num_columns] =
|
||||
&cf->buffer[i];
|
||||
parsing_token = true;
|
||||
}
|
||||
++i;
|
||||
memmove_s(cf->columns[cf->num_columns] + 1,
|
||||
cf->buffer_size - (cf->columns[cf->num_columns] - cf->buffer),
|
||||
cf->columns[cf->num_columns],
|
||||
&cf->buffer[i] - cf->columns[cf->num_columns]);
|
||||
cf->columns[cf->num_columns]++;
|
||||
} else if (cf->buffer[i] == '"') {
|
||||
quotation = false;
|
||||
parsing_token = false;
|
||||
cf->buffer[i] = 0;
|
||||
} else if (!parsing_token) { /* start of an cf->buffer */
|
||||
cf->columns[cf->num_columns] = &cf->buffer[i];
|
||||
parsing_token = true;
|
||||
}
|
||||
} else { /* handling text outside quotation mark */
|
||||
if (cf->buffer[i] == cf->csv_separator) {
|
||||
(cf->num_columns)++;
|
||||
if (ensure_items_array(cf)) {
|
||||
return FAILURE;
|
||||
}
|
||||
cf->columns[cf->num_columns] = 0;
|
||||
parsing_token = false;
|
||||
cf->buffer[i] = 0;
|
||||
for (j = i - spaces_at_end; j != i; ++j) {
|
||||
cf->buffer[j] = 0;
|
||||
}
|
||||
|
||||
} else if (cf->buffer[i] == '"') {
|
||||
quotation = true;
|
||||
spaces_at_end = 0;
|
||||
} else if (cf->csv_comment
|
||||
&& cf->buffer[i] == cf->csv_comment) {
|
||||
cf->buffer[i] = 0;
|
||||
break;
|
||||
} else if (!isspace(cf->buffer[i])) {
|
||||
if (!parsing_token) { /* start of an cf->buffer */
|
||||
if (!cf->columns[cf->num_columns]) {
|
||||
cf->columns[cf->num_columns] =
|
||||
&cf->buffer[i];
|
||||
}
|
||||
parsing_token = true;
|
||||
}
|
||||
spaces_at_end = 0;
|
||||
} else { /* no token.; clear spaces, possibly */
|
||||
parsing_token = false;
|
||||
spaces_at_end++;
|
||||
}
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
for (j = i - spaces_at_end; j != i; ++j) {
|
||||
cf->buffer[j] = 0;
|
||||
}
|
||||
|
||||
/*always consider empty line to have exactly one empty column */
|
||||
cf->num_columns++;
|
||||
|
||||
for (j = 0; j != cf->num_columns; ++j) {
|
||||
/* if no columns were detected during parse, make sure that columns[x]
|
||||
* points to an empty string and not into (NULL) */
|
||||
if (!cf->columns[j]) { /* so that empty columns will return empty string and
|
||||
not a null-pointer */
|
||||
cf->columns[j] = &cf->buffer[i];
|
||||
}
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
unsigned int csv_count_cols(CSVFILE *line)
|
||||
{
|
||||
return line->num_columns;
|
||||
}
|
||||
|
||||
int csv_empty_line(CSVFILE *cf)
|
||||
{
|
||||
if (!csv_is_valid(cf)) {
|
||||
return FAILURE;
|
||||
}
|
||||
if (0 == csv_count_cols(cf)) {
|
||||
return 1;
|
||||
} else if (1 == csv_count_cols(cf)) {
|
||||
const char *value = csv_get_col(cf, 0);
|
||||
if (strempty(value)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *csv_get_col(CSVFILE *cf, int coln)
|
||||
{
|
||||
if (!csv_is_valid(cf)) {
|
||||
return NULL;
|
||||
}
|
||||
return cf->columns[coln];
|
||||
}
|
||||
|
||||
char **csv_get_col_ptr(CSVFILE *cf)
|
||||
{
|
||||
return cf->columns;
|
||||
}
|
||||
|
||||
void csv_seek_beg(CSVFILE *cf)
|
||||
{
|
||||
fseek(cf->f, 0, SEEK_SET);
|
||||
}
|
||||
|
||||
int csv_feof(CSVFILE *cf)
|
||||
{
|
||||
return feof(cf->f);
|
||||
}
|
||||
|
||||
int csv_print(const char *path)
|
||||
{
|
||||
int i, j, k; /* column, line, row, within column */
|
||||
int num_col_lengths = DEF_ALLOC_COL_PTRS;
|
||||
static const int def_col_len = 5;
|
||||
int actual_num_cols = 1;
|
||||
|
||||
CSVFILE *cf = csv_open(path, "r");
|
||||
if (!cf) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
int *col_lengths = malloc(num_col_lengths * sizeof(int));
|
||||
if (!col_lengths) {
|
||||
csv_close(cf);
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
for (i = 0; i != num_col_lengths; ++i) {
|
||||
col_lengths[i] = def_col_len;
|
||||
}
|
||||
|
||||
/*calculate length of each column */
|
||||
i = j = 0;
|
||||
while (!csv_read(cf)) {
|
||||
int num_cols = csv_count_cols(cf);
|
||||
if (num_cols > actual_num_cols) {
|
||||
actual_num_cols = num_cols;
|
||||
}
|
||||
|
||||
if (num_cols > num_col_lengths) {
|
||||
/* CSV file happens to have more columns, than we have allocated
|
||||
* memory for */
|
||||
int *tmp =
|
||||
realloc(col_lengths, num_cols * 2 * sizeof(int));
|
||||
if (!tmp) {
|
||||
free(col_lengths);
|
||||
csv_close(cf);
|
||||
return FAILURE;
|
||||
}
|
||||
/* reallocation successful */
|
||||
col_lengths = tmp;
|
||||
for (i = num_col_lengths; i != num_cols * 2; ++i) {
|
||||
col_lengths[i] = def_col_len;
|
||||
}
|
||||
num_col_lengths = num_cols * 2;
|
||||
}
|
||||
|
||||
for (i = 0; i != csv_count_cols(cf); ++i) {
|
||||
int len = strnlen(csv_get_col(cf, i), MAX_STR_LEN);
|
||||
if (col_lengths[i] < len) {
|
||||
col_lengths[i] = len;
|
||||
}
|
||||
}
|
||||
++j;
|
||||
}
|
||||
|
||||
/*actually format pretty table */
|
||||
csv_seek_beg(cf);
|
||||
printf(" | ");
|
||||
|
||||
for (i = 0; i != actual_num_cols; ++i) {
|
||||
int before = col_lengths[i] / 2;
|
||||
|
||||
for (k = 0; k != before; ++k) {
|
||||
putchar(' ');
|
||||
}
|
||||
putchar(i + 'A');
|
||||
for (k = 0; k != col_lengths[i] - before - 1; ++k) {
|
||||
putchar(' ');
|
||||
}
|
||||
printf(" | ");
|
||||
}
|
||||
printf("\n-----|-");
|
||||
|
||||
for (i = 0; i != actual_num_cols; ++i) {
|
||||
for (k = 0; k != col_lengths[i]; ++k) {
|
||||
putchar('-');
|
||||
}
|
||||
printf("-|-");
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
j = 1;
|
||||
while (!csv_read(cf)) {
|
||||
printf("%4d | ", j);
|
||||
int num_cols = csv_count_cols(cf);
|
||||
for (i = 0; i != actual_num_cols; ++i) {
|
||||
if (i < num_cols) {
|
||||
char *c = csv_get_col(cf, i);
|
||||
for (k = 0; c[k]; k++) {
|
||||
putchar(c[k]);
|
||||
}
|
||||
} else {
|
||||
k = 0;
|
||||
}
|
||||
for (; k != col_lengths[i]; ++k) {
|
||||
putchar(' ');
|
||||
}
|
||||
printf(" | ");
|
||||
}
|
||||
++j;
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
free(col_lengths);
|
||||
csv_close(cf);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
#ifdef __CSV_SAMPLE__
|
||||
/**
|
||||
* usage example for csvparse library
|
||||
* gcc -ggdb csvparse.c -I../common -D__CSV_SAMPLE__ -ocsvsample
|
||||
*/
|
||||
int main()
|
||||
{
|
||||
puts("Validated configurations to run Intel CAS");
|
||||
csv_print("../../tools/build_installer/utils/validated_configurations.csv");
|
||||
putchar('\n');
|
||||
|
||||
puts("IO Classes for Intel CAS");
|
||||
csv_print("../../tools/build_installer/utils/default_ioclasses.csv");
|
||||
putchar('\n');
|
||||
|
||||
}
|
||||
#endif
|
103
casadm/csvparse.h
Normal file
103
casadm/csvparse.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2019 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#ifndef __CSVPARSE_H_
|
||||
#define __CSVPARSE_H_
|
||||
#include <stdio.h>
|
||||
/**
|
||||
* @file
|
||||
* @brief Generic CSV input/output library
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* data structure holding info about CSV file being read.
|
||||
* @note there is no need to directly manipulate any field of this structure.
|
||||
* Csvparse library handles everything.
|
||||
*/
|
||||
struct CSVFILE_t;
|
||||
|
||||
/**
|
||||
* This is to mimic semantics of stdio FILE*, which also is a typedef for a structure.
|
||||
*/
|
||||
typedef struct CSVFILE_t CSVFILE;
|
||||
|
||||
|
||||
CSVFILE *csv_open(const char *path, const char *mode);
|
||||
|
||||
CSVFILE *csv_fopen(FILE *f);
|
||||
CSVFILE *csv_fdopen(int fd);
|
||||
|
||||
|
||||
/**
|
||||
* close csv file. this is a direct counterpart to csv_open
|
||||
*/
|
||||
void csv_close(CSVFILE *cf);
|
||||
|
||||
/**
|
||||
* close a csv without closing underlying plain fle object (so that all
|
||||
* structures allocated by csv parsere are freed but syscall close(2) isn't issued
|
||||
* - this is designed as counterpart to csv_fopen or csv_fdopen
|
||||
*/
|
||||
void csv_close_nu(CSVFILE *cf);
|
||||
|
||||
/**
|
||||
* @param cf csv file handle to read
|
||||
*
|
||||
* Read line from CSV file; return 0 if line was successfully read
|
||||
* return nonzero if eof or error was observed
|
||||
* Error may mean end of file or i.e. memory allocation error for temporary buffers
|
||||
*/
|
||||
int csv_read(CSVFILE *cf);
|
||||
|
||||
/**
|
||||
* @return true if end of file occured.
|
||||
*/
|
||||
int csv_feof(CSVFILE *cf);
|
||||
|
||||
/**
|
||||
* return number of columns
|
||||
* @return # of columns in a csv file
|
||||
*/
|
||||
unsigned int csv_count_cols(CSVFILE *line);
|
||||
|
||||
/**
|
||||
* return given column of recently read row
|
||||
* @param coln - column number
|
||||
* @return pointer to field of csv file as a string; no range checking is performed,
|
||||
* so if coln given exceeds actual number of columns defined in this row, error will occur
|
||||
*/
|
||||
char* csv_get_col(CSVFILE *cf, int coln);
|
||||
|
||||
/**
|
||||
* return entire row as a set of pointers to individual columns (unchecked function
|
||||
* returns internal representation. state is guaranteed to be correct only when
|
||||
* csv_read returned success;
|
||||
*/
|
||||
char** csv_get_col_ptr(CSVFILE *cf);
|
||||
|
||||
/**
|
||||
* Check if current line is empty
|
||||
*
|
||||
* @param cf - CVS file instance
|
||||
* @retval 1 - empty line
|
||||
* @retval 0 - no empty line
|
||||
*/
|
||||
int csv_empty_line(CSVFILE *cf);
|
||||
|
||||
/**
|
||||
* Seek to the begining of CSV file; this allows reading file again, from the begining
|
||||
*/
|
||||
void csv_seek_beg(CSVFILE *cf);
|
||||
|
||||
/**
|
||||
* This function prints CVS file in human readable format to the STD output
|
||||
*
|
||||
* @param path - Path to the CVS file
|
||||
* @return Operation status. 0 - Success, otherwise error during printing
|
||||
*/
|
||||
int csv_print(const char *path);
|
||||
|
||||
#endif
|
244
casadm/extended_err_msg.c
Normal file
244
casadm/extended_err_msg.c
Normal file
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2019 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "safeclib/safe_lib.h"
|
||||
#include <cas_ioctl_codes.h>
|
||||
#include "extended_err_msg.h"
|
||||
|
||||
struct {
|
||||
int cas_error;
|
||||
const char *msg;
|
||||
} static cas_error_code_map[] = {
|
||||
|
||||
/* IOC error mappings*/
|
||||
{
|
||||
OCF_ERR_INVAL,
|
||||
"Invalid input parameter"
|
||||
},
|
||||
{
|
||||
OCF_ERR_INVAL_VOLUME_TYPE,
|
||||
"Invalid volume type"
|
||||
},
|
||||
{
|
||||
OCF_ERR_INTR,
|
||||
"Interrupted by a signal"
|
||||
},
|
||||
{
|
||||
OCF_ERR_UNKNOWN,
|
||||
"Unknown error occurred"
|
||||
},
|
||||
{
|
||||
OCF_ERR_TOO_MANY_CACHES,
|
||||
"Too many caches"
|
||||
},
|
||||
{
|
||||
OCF_ERR_NO_MEM,
|
||||
"Not enough memory to allocate a new cache device"
|
||||
},
|
||||
{
|
||||
OCF_ERR_NO_FREE_RAM,
|
||||
"Not enough free RAM for cache metadata to start cache"
|
||||
},
|
||||
{
|
||||
OCF_ERR_START_CACHE_FAIL,
|
||||
"Failed to insert cache"
|
||||
},
|
||||
{
|
||||
OCF_ERR_CACHE_IN_USE,
|
||||
"At least one cas device is still in use"
|
||||
},
|
||||
{
|
||||
OCF_ERR_CACHE_NOT_EXIST,
|
||||
"Cache ID does not exist"
|
||||
},
|
||||
{
|
||||
OCF_ERR_CACHE_EXIST,
|
||||
"Cache ID already exists"
|
||||
},
|
||||
{
|
||||
OCF_ERR_TOO_MANY_CORES,
|
||||
"Too many core devices in cache"
|
||||
},
|
||||
{
|
||||
OCF_ERR_CORE_NOT_AVAIL,
|
||||
"Core device not available"
|
||||
},
|
||||
{
|
||||
OCF_ERR_CACHE_NOT_AVAIL,
|
||||
"Cache device not available"
|
||||
},
|
||||
{
|
||||
OCF_ERR_IO_CLASS_NOT_EXIST,
|
||||
"No such IO class ID in the cache"
|
||||
},
|
||||
{
|
||||
OCF_ERR_WRITE_CACHE,
|
||||
"Error while writing to cache device"
|
||||
},
|
||||
{
|
||||
OCF_ERR_WRITE_CORE,
|
||||
"Error while writing to core device"
|
||||
},
|
||||
{
|
||||
OCF_ERR_DIRTY_SHUTDOWN,
|
||||
"Please use --load option to restore previous cache state "
|
||||
"(Warning: data corruption may happen)\nOr initialize your "
|
||||
"cache using --force option. Warning: All dirty data will be "
|
||||
"lost!\n"
|
||||
},
|
||||
{
|
||||
OCF_ERR_DIRTY_EXISTS,
|
||||
"Cache closed with dirty data.\nPlease start cache using "
|
||||
"--load or --force option.\n"
|
||||
},
|
||||
{
|
||||
OCF_ERR_FLUSHING_INTERRUPTED,
|
||||
"Flushing of core interrupted"
|
||||
},
|
||||
{
|
||||
OCF_ERR_CANNOT_ADD_CORE_TO_POOL,
|
||||
"Error occurred during adding core device to core pool"
|
||||
},
|
||||
{
|
||||
OCF_ERR_CACHE_IN_INCOMPLETE_STATE,
|
||||
"Cache is in incomplete state - at least one core is inactive"
|
||||
},
|
||||
{
|
||||
OCF_ERR_CORE_IN_INACTIVE_STATE,
|
||||
"Core device is in inactive state"
|
||||
},
|
||||
{
|
||||
OCF_ERR_NOT_OPEN_EXC,
|
||||
"Cannot open device exclusively"
|
||||
},
|
||||
|
||||
/* CAS kernel error mappings*/
|
||||
{
|
||||
KCAS_ERR_ROOT,
|
||||
"Must be root"
|
||||
},
|
||||
{
|
||||
KCAS_ERR_SYSTEM,
|
||||
"System Error"
|
||||
},
|
||||
{
|
||||
KCAS_ERR_BAD_RANGE,
|
||||
"Range parameters are invalid"
|
||||
},
|
||||
{
|
||||
KCAS_ERR_DEV_SPACE,
|
||||
"Illegal range, out of device space"
|
||||
},
|
||||
{
|
||||
KCAS_ERR_INV_IOCTL,
|
||||
"Invalid ioctl"
|
||||
},
|
||||
{
|
||||
KCAS_ERR_DEV_PENDING,
|
||||
"Device opens or mount are pending to this cache"
|
||||
},
|
||||
{
|
||||
KCAS_ERR_DIRTY_EXISTS_NVME,
|
||||
"Cache device contains dirty data.\nIf you want to format it, "
|
||||
"please use --force option.\nWarning: all data will be lost!"
|
||||
},
|
||||
{
|
||||
KCAS_ERR_FILE_EXISTS,
|
||||
"Could not create exported object because file in /dev "
|
||||
"directory exists"
|
||||
},
|
||||
{
|
||||
KCAS_ERR_IN_UPGRADE,
|
||||
"Operation not allowed. CAS is in upgrade state"
|
||||
},
|
||||
{
|
||||
KCAS_ERR_UNALIGNED,
|
||||
"Cache device logical sector size is greater than core device "
|
||||
"logical sector size.\nConsider changing logical sector size "
|
||||
"on current cache device \nor try other device with the same "
|
||||
"logical sector size as core device."
|
||||
},
|
||||
{
|
||||
KCAS_ERR_NO_STORED_CONF,
|
||||
"Internal kernel module error" },
|
||||
{
|
||||
KCAS_ERR_ROLLBACK,
|
||||
"Cannot restore previous configuration"
|
||||
},
|
||||
{
|
||||
KCAS_ERR_NOT_NVME,
|
||||
"Given block device is not NVMe"
|
||||
},
|
||||
{
|
||||
KCAS_ERR_FORMAT_FAILED,
|
||||
"Failed to format NVMe device"
|
||||
},
|
||||
{
|
||||
KCAS_ERR_NVME_BAD_FORMAT,
|
||||
"NVMe is formatted to unsupported format"
|
||||
},
|
||||
{
|
||||
KCAS_ERR_CONTAINS_PART,
|
||||
"Device contains partitions.\nIf you want to continue, "
|
||||
"please use --force option.\nWarning: all data will be lost!"
|
||||
},
|
||||
{
|
||||
KCAS_ERR_A_PART,
|
||||
"Formatting of partition is unsupported."
|
||||
},
|
||||
{
|
||||
KCAS_ERR_REMOVED_DIRTY,
|
||||
"Flush error occured. Core has been set to detached state.\n"
|
||||
"Warning: Core device may contain inconsistent data.\n"
|
||||
"To access your data please add core back to the cache."
|
||||
},
|
||||
{
|
||||
KCAS_ERR_STOPPED_DIRTY,
|
||||
"Cache has been stopped with flushing error.\n"
|
||||
"Warning: Core devices may contain inconsistent data.\n"
|
||||
"To access your data, please start cache with --load option."
|
||||
},
|
||||
{
|
||||
KCAS_ERR_NO_CACHE_ATTACHED,
|
||||
"Operation not allowed. Caching device is not attached."
|
||||
},
|
||||
{
|
||||
KCAS_ERR_CORE_POOL_NOT_EMPTY,
|
||||
"Operation not allowed. Core pool is not empty."
|
||||
},
|
||||
{
|
||||
KCAS_ERR_CLS_RULE_UNKNOWN_CONDITION,
|
||||
"Unexpected classification rule condition"
|
||||
},
|
||||
{
|
||||
KCAS_ERR_CLS_RULE_INVALID_SYNTAX,
|
||||
"Invalid classification rule syntax"
|
||||
},
|
||||
|
||||
|
||||
};
|
||||
|
||||
const char *cas_strerr(int cas_error_code)
|
||||
{
|
||||
int i;
|
||||
int count = sizeof(cas_error_code_map) / sizeof(cas_error_code_map[0]);
|
||||
|
||||
if (cas_error_code == 0)
|
||||
return NULL; /* No Error */
|
||||
|
||||
cas_error_code = abs(cas_error_code);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (cas_error_code_map[i].cas_error == cas_error_code)
|
||||
return cas_error_code_map[i].msg;
|
||||
}
|
||||
|
||||
return strerror(cas_error_code);
|
||||
}
|
||||
|
6
casadm/extended_err_msg.h
Normal file
6
casadm/extended_err_msg.h
Normal file
@@ -0,0 +1,6 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2019 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
const char *cas_strerr(int cas_error_code);
|
110
casadm/intvector.c
Normal file
110
casadm/intvector.c
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2019 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "intvector.h"
|
||||
|
||||
#define DEFAULT_CAPACITY 11
|
||||
|
||||
|
||||
struct intvector *vector_alloc()
|
||||
{
|
||||
struct intvector *v = malloc(sizeof(struct intvector));
|
||||
if (!v) {
|
||||
return 0;
|
||||
}
|
||||
if (vector_alloc_placement(v)) {
|
||||
free(v);
|
||||
return 0;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
int vector_alloc_placement(struct intvector *v)
|
||||
{
|
||||
v->content = malloc(sizeof(int) * DEFAULT_CAPACITY);
|
||||
if (!v->content) {
|
||||
return 1;
|
||||
}
|
||||
v->size = 0;
|
||||
v->capacity = DEFAULT_CAPACITY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vector_reserve(struct intvector *v, int s)
|
||||
{
|
||||
if (s < DEFAULT_CAPACITY || s < v->capacity) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *tmp = realloc(v->content, s*sizeof(int));
|
||||
if (!tmp) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
v->content = tmp;
|
||||
v->capacity = s;
|
||||
return 0;
|
||||
}
|
||||
void vector_free_placement(struct intvector *v)
|
||||
{
|
||||
free(v->content);
|
||||
}
|
||||
|
||||
void vector_free(struct intvector *v)
|
||||
{
|
||||
vector_free_placement(v);
|
||||
free(v);
|
||||
}
|
||||
|
||||
int vector_get(struct intvector *v, int i)
|
||||
{
|
||||
return v->content[i];
|
||||
}
|
||||
|
||||
int vector_set(struct intvector *v, int i, int x)
|
||||
{
|
||||
v->content[i]=x;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vector_zero(struct intvector *v)
|
||||
{
|
||||
memset(v->content, 0, sizeof(int) * v->size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vector_push_back(struct intvector *v, int x)
|
||||
{
|
||||
if (vector_capacity(v) == vector_size(v)) {
|
||||
if (vector_reserve(v, v->size*2)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
vector_set(v, v->size, x);
|
||||
v->size++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vector_size(struct intvector *v)
|
||||
{
|
||||
return v->size;
|
||||
}
|
||||
|
||||
int vector_capacity(struct intvector *v)
|
||||
{
|
||||
return v->capacity;
|
||||
}
|
||||
|
||||
int vector_resize(struct intvector *v, int s)
|
||||
{
|
||||
if (vector_reserve(v, s)) {
|
||||
return 1;
|
||||
}
|
||||
v->size = s;
|
||||
return 0;
|
||||
}
|
40
casadm/intvector.h
Normal file
40
casadm/intvector.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2019 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#ifndef __INTVECTOR_H
|
||||
#define __INTVECTOR_H
|
||||
struct intvector
|
||||
{
|
||||
int capacity;
|
||||
int size;
|
||||
int *content;
|
||||
};
|
||||
/* names of these functions (mostly) correspond to std::vector */
|
||||
|
||||
struct intvector *vector_alloc();
|
||||
|
||||
int vector_alloc_placement(struct intvector *v);
|
||||
|
||||
int vector_reserve(struct intvector *v, int s);
|
||||
|
||||
void vector_free(struct intvector *v);
|
||||
|
||||
void vector_free_placement(struct intvector *v);
|
||||
|
||||
int vector_get(struct intvector *v, int i);
|
||||
|
||||
int vector_set(struct intvector *v, int i, int x);
|
||||
|
||||
int vector_zero(struct intvector *v);
|
||||
|
||||
int vector_push_back(struct intvector *v, int x);
|
||||
|
||||
int vector_size(struct intvector *v);
|
||||
|
||||
int vector_capacity(struct intvector *v);
|
||||
|
||||
int vector_resize(struct intvector *v, int s);
|
||||
|
||||
#endif
|
27
casadm/ocf_env.h
Normal file
27
casadm/ocf_env.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2019 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#ifndef OCF_ENV_H_
|
||||
#define OCF_ENV_H_
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "safeclib/safe_lib.h"
|
||||
|
||||
#define min(x, y) ({ x < y ? x : y; })
|
||||
|
||||
#define ENV_BUG_ON(cond) ({ if (cond) exit(1); })
|
||||
|
||||
/* *** STRING OPERATIONS *** */
|
||||
|
||||
#define env_memset memset_s
|
||||
#define env_memcpy memcpy_s
|
||||
#define env_memcmp memcmp_s
|
||||
|
||||
#define env_strnlen strnlen_s
|
||||
#define env_strncmp strncmp
|
||||
#define env_strncpy strncpy_s
|
||||
|
||||
#endif /* OCF_ENV_H_ */
|
22
casadm/ocf_env_headers.h
Normal file
22
casadm/ocf_env_headers.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2019 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#ifndef __OCF_ENV_HEADERS_H__
|
||||
#define __OCF_ENV_HEADERS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/* TODO: Move prefix printing to context logger. */
|
||||
#define OCF_LOGO "CAS"
|
||||
#define OCF_PREFIX_SHORT "[" OCF_LOGO "] "
|
||||
#define OCF_PREFIX_LONG "Cache Acceleration Software Linux"
|
||||
|
||||
#define OCF_VERSION_MAIN CAS_VERSION_MAIN
|
||||
#define OCF_VERSION_MAJOR CAS_VERSION_MAJOR
|
||||
#define OCF_VERSION_MINOR CAS_VERSION_MINOR
|
||||
|
||||
#endif /* __OCF_ENV_HEADERS_H__ */
|
198
casadm/psort.c
Normal file
198
casadm/psort.c
Normal file
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2019 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/timeb.h>
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include "safeclib/safe_mem_lib.h"
|
||||
#include "psort.h"
|
||||
|
||||
/**
|
||||
* internal state of parallel sort algorithm (entire task for main thread,
|
||||
* subtask for children).
|
||||
*/
|
||||
struct psort_state
|
||||
{
|
||||
void *defbase; /*!< base of master buffer sort
|
||||
* - needed to compute offsets*/
|
||||
int spawn_threads;
|
||||
void *base; /*!< base of subtask */
|
||||
size_t nmemb; /*!< number of members in subtask */
|
||||
size_t size; /*!< of each member */
|
||||
compar_t compar;
|
||||
int result; /*!< partial result */
|
||||
void *tmpbuf; /*!< temporary buffer for purpose of merge algorithm */
|
||||
};
|
||||
|
||||
void memcpy_replacement(void *dst, void *src, size_t size)
|
||||
{
|
||||
/**
|
||||
* Avoid this if possible. memcpy_s leads to crappy performance
|
||||
* defeating purpose of entire optimized sort.
|
||||
*/
|
||||
memcpy_s(dst, size, src, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* merge algorithm has O(N) spatial complexity and O(N) time complexity
|
||||
*/
|
||||
void merge_ranges(void *base, size_t nmemb1, size_t nmemb2, size_t size,
|
||||
compar_t compar, void *tmpbuf)
|
||||
{
|
||||
void *target_buf = tmpbuf;
|
||||
int i1, i2;
|
||||
|
||||
for (i1 = i2 = 0; i1 < nmemb1 || i2 < nmemb2;) {
|
||||
bool lil; /* lil means "left is less" */
|
||||
if (i1 == nmemb1) {
|
||||
lil = false;
|
||||
} else if (i2 ==nmemb2) {
|
||||
lil = true;
|
||||
} else if (compar(base + i1 * size,
|
||||
base + (nmemb1 +i2) * size) < 0) {
|
||||
lil = true;
|
||||
} else {
|
||||
lil = false;
|
||||
|
||||
}
|
||||
if (lil) {
|
||||
memcpy_replacement(target_buf + (i1 + i2) * size,
|
||||
base + i1 * size,
|
||||
size);
|
||||
i1++;
|
||||
} else {
|
||||
memcpy_replacement(target_buf + (i1 + i2) * size,
|
||||
base + (nmemb1 + i2) * size,
|
||||
size);
|
||||
i2++;
|
||||
}
|
||||
}
|
||||
memcpy_replacement(base, target_buf, (nmemb1 + nmemb2) * size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute quicksort on part or entirety of subrange. If subranges taken into
|
||||
* account, than merge partial sort results.
|
||||
*
|
||||
* Complexity | time | spatial
|
||||
* --------------------+-------------------+-----------
|
||||
* Quick Sort | O(n*lg(n)/ncpu) | O(1)
|
||||
* Merging | O(n) | O(N)
|
||||
* --------------------+-------------------+-----------
|
||||
* Entire algorithm | O(n+n*lg(n)/ncpu) | O(N)
|
||||
*
|
||||
* Effectively for suficiently large number of CPUs, sorting time
|
||||
* becomes linear to dataset:
|
||||
* \lim{ncpu \rightarrow \infty} O(n+\frac{n*lg(n)}{ncpu}) = O(n + 0^+) = O(n)
|
||||
* Less can't be achieved, as last merge can't be parallelized.
|
||||
*/
|
||||
void *psort_thread_fun(void *arg_v)
|
||||
{
|
||||
pthread_t thread;
|
||||
struct psort_state* arg = arg_v;
|
||||
struct psort_state base_state;
|
||||
struct psort_state child_state;
|
||||
memcpy_replacement(&base_state, arg, sizeof(base_state));
|
||||
if (arg->spawn_threads > 1) {
|
||||
/* local state (assume, input state is unmodifiable) */
|
||||
memcpy_replacement(&child_state, arg, sizeof(base_state));
|
||||
|
||||
base_state.spawn_threads /= 2;
|
||||
child_state.spawn_threads = arg->spawn_threads
|
||||
- base_state.spawn_threads;
|
||||
|
||||
base_state.nmemb /= 2;
|
||||
child_state.nmemb = arg->nmemb - base_state.nmemb;
|
||||
|
||||
child_state.base += base_state.size *
|
||||
base_state.nmemb;
|
||||
/* spawn child */
|
||||
if (pthread_create(&thread, 0, psort_thread_fun, &child_state)) {
|
||||
/* failed to create thread */
|
||||
arg->result = -errno;
|
||||
return arg_v;
|
||||
}
|
||||
}
|
||||
|
||||
if (1 == base_state.spawn_threads) {
|
||||
qsort(base_state.base, base_state.nmemb,
|
||||
base_state.size, base_state.compar);
|
||||
} else {
|
||||
psort_thread_fun(&base_state);
|
||||
if (base_state.result) {
|
||||
arg->result = base_state.result;
|
||||
}
|
||||
}
|
||||
|
||||
if (arg->spawn_threads > 1) {
|
||||
if (pthread_join(thread, 0)) {
|
||||
arg->result = -errno;
|
||||
return arg_v;
|
||||
}
|
||||
if (child_state.result) {
|
||||
arg->result = child_state.result;
|
||||
return arg_v;
|
||||
}
|
||||
if (!arg->result) {
|
||||
merge_ranges(arg->base, base_state.nmemb,
|
||||
child_state.nmemb, arg->size,
|
||||
arg->compar,
|
||||
arg->tmpbuf + (base_state.base
|
||||
- base_state.defbase));
|
||||
}
|
||||
}
|
||||
return arg_v;
|
||||
}
|
||||
|
||||
/**
|
||||
* actual parallel sorting entry point
|
||||
*/
|
||||
int psort_main(void *base, size_t nmemb, size_t size,
|
||||
compar_t compar, int ncpu)
|
||||
{
|
||||
struct psort_state base_state;
|
||||
/* use half the number of logical CPUs for purpose of sorting */
|
||||
base_state.spawn_threads = ncpu;
|
||||
/* current num of CPUs */
|
||||
base_state.defbase = base;
|
||||
base_state.base = base;
|
||||
base_state.nmemb = nmemb;
|
||||
base_state.size = size;
|
||||
base_state.compar = compar;
|
||||
base_state.tmpbuf = malloc(size * nmemb);
|
||||
base_state.result = 0;
|
||||
if (!base_state.tmpbuf) {
|
||||
return -1;
|
||||
}
|
||||
psort_thread_fun(&base_state);
|
||||
free(base_state.tmpbuf);
|
||||
return base_state.result;
|
||||
}
|
||||
|
||||
void psort(void *base, size_t nmemb, size_t size,
|
||||
compar_t compar)
|
||||
{
|
||||
/* entry point to psort */
|
||||
int ncpu = sysconf(_SC_NPROCESSORS_ONLN)/2;
|
||||
int maxncpu = nmemb / 1024;
|
||||
if (maxncpu < ncpu) {
|
||||
ncpu = maxncpu;
|
||||
}
|
||||
/* don't invoke actual psort when less than 2 threads are needed */
|
||||
if (ncpu < 2) {
|
||||
qsort(base, nmemb, size, compar);
|
||||
} else {
|
||||
if (psort_main(base, nmemb, size, compar, ncpu)) {
|
||||
/* if parallel sorting failed (i.e. due to failed thread
|
||||
* creation, fall back to single threaded operation */
|
||||
qsort(base, nmemb, size, compar);
|
||||
}
|
||||
}
|
||||
}
|
22
casadm/psort.h
Normal file
22
casadm/psort.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2019 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#ifndef PSORT_H
|
||||
#define PSORT_H
|
||||
typedef int (*compar_t)(const void *, const void *);
|
||||
|
||||
/**
|
||||
* function does exactly the same thing as qsort, except, that it sorts
|
||||
* using many CPU cores, not just one.
|
||||
*
|
||||
* number of CPU cores is configured as half of the number of online
|
||||
* CPUs in the system.
|
||||
*/
|
||||
void psort(void *base, size_t nmemb, size_t size,
|
||||
compar_t compar);
|
||||
|
||||
|
||||
#endif
|
||||
|
72
casadm/safeclib/ignore_handler_s.c
Normal file
72
casadm/safeclib/ignore_handler_s.c
Normal file
@@ -0,0 +1,72 @@
|
||||
/*------------------------------------------------------------------
|
||||
* ignore_handler_s.c
|
||||
*
|
||||
* 2012, Jonathan Toppins <jtoppins@users.sourceforge.net>
|
||||
*
|
||||
* Copyright (c) 2012 Cisco Systems
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "safeclib_private.h"
|
||||
|
||||
/**
|
||||
* NAME
|
||||
* ignore_handler_s
|
||||
*
|
||||
* SYNOPSIS
|
||||
* #include "safe_lib.h"
|
||||
* void ignore_handler_s(const char *msg, void *ptr, errno_t error)
|
||||
*
|
||||
* DESCRIPTION
|
||||
* This function simply returns to the caller.
|
||||
*
|
||||
* SPECIFIED IN
|
||||
* ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments
|
||||
* and system software interfaces, Extensions to the C Library,
|
||||
* Part I: Bounds-checking interfaces
|
||||
*
|
||||
* INPUT PARAMETERS
|
||||
* msg Pointer to the message describing the error
|
||||
*
|
||||
* ptr Pointer to aassociated data. Can be NULL.
|
||||
*
|
||||
* error The error code encountered.
|
||||
*
|
||||
* RETURN VALUE
|
||||
* Returns no value.
|
||||
*
|
||||
* ALSO SEE
|
||||
* abort_handler_s()
|
||||
*
|
||||
*/
|
||||
|
||||
void ignore_handler_s(const char *msg, void *ptr, errno_t error)
|
||||
{
|
||||
|
||||
sldebug_printf("IGNORE CONSTRAINT HANDLER: (%u) %s\n", error,
|
||||
(msg) ? msg : "Null message");
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL(ignore_handler_s);
|
853
casadm/safeclib/mem_primitives_lib.c
Normal file
853
casadm/safeclib/mem_primitives_lib.c
Normal file
@@ -0,0 +1,853 @@
|
||||
/*------------------------------------------------------------------
|
||||
* mem_primitives_lib.c - Unguarded Memory Copy Routines
|
||||
*
|
||||
* February 2005, Bo Berry
|
||||
*
|
||||
* Copyright (c) 2005-2009 Cisco Systems
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "mem_primitives_lib.h"
|
||||
|
||||
/*
|
||||
* mem_primitives_lib.c provides unguarded memory routines
|
||||
* that are used by the safe_mem_library. These routines
|
||||
* may also be used by an application, but the application
|
||||
* is responsible for all parameter validation and alignment.
|
||||
*/
|
||||
|
||||
/**
|
||||
* NAME
|
||||
* mem_prim_set - Sets memory to value
|
||||
*
|
||||
* SYNOPSIS
|
||||
* #include "mem_primitives_lib.h"
|
||||
* void
|
||||
* mem_prim_set(void *dest, uint32_t len, uint8_t value)
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Sets len bytes starting at dest to the specified value
|
||||
*
|
||||
* INPUT PARAMETERS
|
||||
* dest - pointer to memory that will be set to value
|
||||
*
|
||||
* len - number of bytes to be set
|
||||
*
|
||||
* value - byte value
|
||||
*
|
||||
* OUTPUT PARAMETERS
|
||||
* dest - is updated
|
||||
*
|
||||
* RETURN VALUE
|
||||
* none
|
||||
*
|
||||
*/
|
||||
void
|
||||
mem_prim_set (void *dest, uint32_t len, uint8_t value)
|
||||
{
|
||||
uint8_t *dp;
|
||||
uint32_t count;
|
||||
uint32_t lcount;
|
||||
|
||||
uint32_t *lp;
|
||||
uint32_t value32;
|
||||
|
||||
count = len;
|
||||
|
||||
dp = dest;
|
||||
|
||||
value32 = value | (value << 8) | (value << 16) | (value << 24);
|
||||
|
||||
/*
|
||||
* First, do the few bytes to get uint32_t aligned.
|
||||
*/
|
||||
for (; count && ( (uintptr_t)dp & (sizeof(uint32_t)-1) ); count--) {
|
||||
*dp++ = value;
|
||||
}
|
||||
|
||||
/*
|
||||
* Then do the uint32_ts, unrolled the loop for performance
|
||||
*/
|
||||
lp = (uint32_t *)dp;
|
||||
lcount = count >> 2;
|
||||
|
||||
while (lcount != 0) {
|
||||
|
||||
switch (lcount) {
|
||||
/*
|
||||
* Here we do blocks of 8. Once the remaining count
|
||||
* drops below 8, take the fast track to finish up.
|
||||
*/
|
||||
default:
|
||||
*lp++ = value32; *lp++ = value32; *lp++ = value32; *lp++ = value32;
|
||||
*lp++ = value32; *lp++ = value32; *lp++ = value32; *lp++ = value32;
|
||||
*lp++ = value32; *lp++ = value32; *lp++ = value32; *lp++ = value32;
|
||||
*lp++ = value32; *lp++ = value32; *lp++ = value32; *lp++ = value32;
|
||||
lcount -= 16;
|
||||
break;
|
||||
|
||||
case 15: *lp++ = value32;
|
||||
case 14: *lp++ = value32;
|
||||
case 13: *lp++ = value32;
|
||||
case 12: *lp++ = value32;
|
||||
case 11: *lp++ = value32;
|
||||
case 10: *lp++ = value32;
|
||||
case 9: *lp++ = value32;
|
||||
case 8: *lp++ = value32;
|
||||
|
||||
case 7: *lp++ = value32;
|
||||
case 6: *lp++ = value32;
|
||||
case 5: *lp++ = value32;
|
||||
case 4: *lp++ = value32;
|
||||
case 3: *lp++ = value32;
|
||||
case 2: *lp++ = value32;
|
||||
case 1: *lp++ = value32;
|
||||
lcount = 0;
|
||||
break;
|
||||
}
|
||||
} /* end while */
|
||||
|
||||
|
||||
dp = (uint8_t *)lp;
|
||||
|
||||
/*
|
||||
* compute the number of remaining bytes
|
||||
*/
|
||||
count &= (sizeof(uint32_t)-1);
|
||||
|
||||
/*
|
||||
* remaining bytes
|
||||
*/
|
||||
for (; count; dp++, count--) {
|
||||
*dp = value;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* NAME
|
||||
* mem_prim_set16 - Sets memory to value
|
||||
*
|
||||
* SYNOPSIS
|
||||
* #include "mem_primitives_lib.h"
|
||||
* void
|
||||
* mem_prim_set16(uint16_t *dp, uint32_t len, uint16_t value)
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Sets len uint16_ts starting at dest to the specified value.
|
||||
* Pointers must meet system alignment requirements.
|
||||
*
|
||||
* INPUT PARAMETERS
|
||||
* dest - pointer to memory that will be set to value
|
||||
*
|
||||
* len - number of uint16_ts to be set
|
||||
*
|
||||
* value - uint16_t value
|
||||
*
|
||||
* OUTPUT PARAMETERS
|
||||
* dest - is updated
|
||||
*
|
||||
* RETURN VALUE
|
||||
* none
|
||||
*
|
||||
*/
|
||||
void
|
||||
mem_prim_set16 (uint16_t *dp, uint32_t len, uint16_t value)
|
||||
{
|
||||
|
||||
while (len != 0) {
|
||||
|
||||
switch (len) {
|
||||
/*
|
||||
* Here we do blocks of 8. Once the remaining count
|
||||
* drops below 8, take the fast track to finish up.
|
||||
*/
|
||||
default:
|
||||
*dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value;
|
||||
*dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value;
|
||||
*dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value;
|
||||
*dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value;
|
||||
len -= 16;
|
||||
break;
|
||||
|
||||
case 15: *dp++ = value;
|
||||
case 14: *dp++ = value;
|
||||
case 13: *dp++ = value;
|
||||
case 12: *dp++ = value;
|
||||
case 11: *dp++ = value;
|
||||
case 10: *dp++ = value;
|
||||
case 9: *dp++ = value;
|
||||
case 8: *dp++ = value;
|
||||
|
||||
case 7: *dp++ = value;
|
||||
case 6: *dp++ = value;
|
||||
case 5: *dp++ = value;
|
||||
case 4: *dp++ = value;
|
||||
case 3: *dp++ = value;
|
||||
case 2: *dp++ = value;
|
||||
case 1: *dp++ = value;
|
||||
len = 0;
|
||||
break;
|
||||
}
|
||||
} /* end while */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* NAME
|
||||
* mem_prim_set32 - Sets memory to the uint32_t value
|
||||
*
|
||||
* SYNOPSIS
|
||||
* #include "mem_primitives_lib.h"
|
||||
* void
|
||||
* mem_prim_set32(uint32_t *dp, uint32_t len, uint32_t value)
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Sets len uint32_ts starting at dest to the specified value
|
||||
* Pointers must meet system alignment requirements.
|
||||
*
|
||||
* INPUT PARAMETERS
|
||||
* dest - pointer to memory that will be set to value
|
||||
*
|
||||
* len - number of uint32_ts to be set
|
||||
*
|
||||
* value - uint32_t value
|
||||
*
|
||||
* OUTPUT PARAMETERS
|
||||
* dest - is updated
|
||||
*
|
||||
* RETURN VALUE
|
||||
* none
|
||||
*
|
||||
*/
|
||||
void
|
||||
mem_prim_set32 (uint32_t *dp, uint32_t len, uint32_t value)
|
||||
{
|
||||
|
||||
while (len != 0) {
|
||||
|
||||
switch (len) {
|
||||
/*
|
||||
* Here we do blocks of 8. Once the remaining count
|
||||
* drops below 8, take the fast track to finish up.
|
||||
*/
|
||||
default:
|
||||
*dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value;
|
||||
*dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value;
|
||||
*dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value;
|
||||
*dp++ = value; *dp++ = value; *dp++ = value; *dp++ = value;
|
||||
len -= 16;
|
||||
break;
|
||||
|
||||
case 15: *dp++ = value;
|
||||
case 14: *dp++ = value;
|
||||
case 13: *dp++ = value;
|
||||
case 12: *dp++ = value;
|
||||
case 11: *dp++ = value;
|
||||
case 10: *dp++ = value;
|
||||
case 9: *dp++ = value;
|
||||
case 8: *dp++ = value;
|
||||
|
||||
case 7: *dp++ = value;
|
||||
case 6: *dp++ = value;
|
||||
case 5: *dp++ = value;
|
||||
case 4: *dp++ = value;
|
||||
case 3: *dp++ = value;
|
||||
case 2: *dp++ = value;
|
||||
case 1: *dp++ = value;
|
||||
len = 0;
|
||||
break;
|
||||
}
|
||||
} /* end while */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* NAME
|
||||
* mem_prim_move - Move (handles overlap) memory
|
||||
*
|
||||
* SYNOPSIS
|
||||
* #include "mem_primitives_lib.h"
|
||||
* void
|
||||
* mem_prim_move(void *dest, const void *src, uint32_t len)
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Moves at most slen bytes from src to dest, up to dmax
|
||||
* bytes. Dest may overlap with src.
|
||||
*
|
||||
* INPUT PARAMETERS
|
||||
* dest - pointer to the memory that will be replaced by src.
|
||||
*
|
||||
* src - pointer to the memory that will be copied
|
||||
* to dest
|
||||
*
|
||||
* len - maximum number bytes of src that can be copied
|
||||
*
|
||||
* OUTPUT PARAMETERS
|
||||
* dest - is updated
|
||||
*
|
||||
* RETURN VALUE
|
||||
* none
|
||||
*
|
||||
*/
|
||||
void
|
||||
mem_prim_move (void *dest, const void *src, uint32_t len)
|
||||
{
|
||||
|
||||
#define wsize sizeof(uint32_t)
|
||||
#define wmask (wsize - 1)
|
||||
|
||||
uint8_t *dp = dest;
|
||||
const uint8_t *sp = src;
|
||||
|
||||
uint32_t tsp;
|
||||
|
||||
/*
|
||||
* Determine if we need to copy forward or backward (overlap)
|
||||
*/
|
||||
if ((uintptr_t)dp < (uintptr_t)sp) {
|
||||
/*
|
||||
* Copy forward.
|
||||
*/
|
||||
|
||||
/*
|
||||
* get a working copy of src for bit operations
|
||||
*/
|
||||
tsp = (uintptr_t)sp;
|
||||
|
||||
/*
|
||||
* Try to align both operands. This cannot be done
|
||||
* unless the low bits match.
|
||||
*/
|
||||
if ((tsp | (uintptr_t)dp) & wmask) {
|
||||
/*
|
||||
* determine how many bytes to copy to align operands
|
||||
*/
|
||||
if ((tsp ^ (uintptr_t)dp) & wmask || len < wsize) {
|
||||
tsp = len;
|
||||
|
||||
} else {
|
||||
tsp = wsize - (tsp & wmask);
|
||||
}
|
||||
|
||||
len -= tsp;
|
||||
|
||||
/*
|
||||
* make the alignment
|
||||
*/
|
||||
do {
|
||||
*dp++ = *sp++;
|
||||
} while (--tsp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now copy, then mop up any trailing bytes.
|
||||
*/
|
||||
tsp = len / wsize;
|
||||
|
||||
if (tsp > 0) {
|
||||
|
||||
do {
|
||||
*(uint32_t *)dp = *(uint32_t *)sp;
|
||||
|
||||
sp += wsize;
|
||||
dp += wsize;
|
||||
} while (--tsp);
|
||||
}
|
||||
|
||||
/*
|
||||
* copy over the remaining bytes and we're done
|
||||
*/
|
||||
tsp = len & wmask;
|
||||
|
||||
if (tsp > 0) {
|
||||
do {
|
||||
*dp++ = *sp++;
|
||||
} while (--tsp);
|
||||
}
|
||||
|
||||
} else {
|
||||
/*
|
||||
* This section is used to copy backwards, to handle any
|
||||
* overlap. The alignment requires (tps&wmask) bytes to
|
||||
* align.
|
||||
*/
|
||||
|
||||
/*
|
||||
* go to end of the memory to copy
|
||||
*/
|
||||
sp += len;
|
||||
dp += len;
|
||||
|
||||
/*
|
||||
* get a working copy of src for bit operations
|
||||
*/
|
||||
tsp = (uintptr_t)sp;
|
||||
|
||||
/*
|
||||
* Try to align both operands.
|
||||
*/
|
||||
if ((tsp | (uintptr_t)dp) & wmask) {
|
||||
|
||||
if ((tsp ^ (uintptr_t)dp) & wmask || len <= wsize) {
|
||||
tsp = len;
|
||||
} else {
|
||||
tsp &= wmask;
|
||||
}
|
||||
|
||||
len -= tsp;
|
||||
|
||||
/*
|
||||
* make the alignment
|
||||
*/
|
||||
do {
|
||||
*--dp = *--sp;
|
||||
} while (--tsp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now copy in uint32_t units, then mop up any trailing bytes.
|
||||
*/
|
||||
tsp = len / wsize;
|
||||
|
||||
if (tsp > 0) {
|
||||
do {
|
||||
sp -= wsize;
|
||||
dp -= wsize;
|
||||
|
||||
*(uint32_t *)dp = *(uint32_t *)sp;
|
||||
} while (--tsp);
|
||||
}
|
||||
|
||||
/*
|
||||
* copy over the remaining bytes and we're done
|
||||
*/
|
||||
tsp = len & wmask;
|
||||
if (tsp > 0) {
|
||||
tsp = len & wmask;
|
||||
do {
|
||||
*--dp = *--sp;
|
||||
} while (--tsp);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* NAME
|
||||
* mem_prim_move8 - Move (handles overlap) memory
|
||||
*
|
||||
* SYNOPSIS
|
||||
* #include "mem_primitives_lib.h"
|
||||
* void
|
||||
* mem_prim_move8(void *dest, const void *src, uint32_t len)
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Moves at most len uint8_ts from sp to dp.
|
||||
* The destination may overlap with source.
|
||||
*
|
||||
* INPUT PARAMETERS
|
||||
* dp - pointer to the memory that will be replaced by sp.
|
||||
*
|
||||
* sp - pointer to the memory that will be copied
|
||||
* to dp
|
||||
*
|
||||
* len - maximum number uint8_t of sp that can be copied
|
||||
*
|
||||
* OUTPUT PARAMETERS
|
||||
* dp - pointer to the memory that will be replaced by sp.
|
||||
*
|
||||
* RETURN VALUE
|
||||
* none
|
||||
*
|
||||
*/
|
||||
void
|
||||
mem_prim_move8 (uint8_t *dp, const uint8_t *sp, uint32_t len)
|
||||
{
|
||||
|
||||
/*
|
||||
* Determine if we need to copy forward or backward (overlap)
|
||||
*/
|
||||
if (dp < sp) {
|
||||
/*
|
||||
* Copy forward.
|
||||
*/
|
||||
|
||||
while (len != 0) {
|
||||
|
||||
switch (len) {
|
||||
/*
|
||||
* Here we do blocks of 8. Once the remaining count
|
||||
* drops below 8, take the fast track to finish up.
|
||||
*/
|
||||
default:
|
||||
*dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++;
|
||||
*dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++;
|
||||
*dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++;
|
||||
*dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++;
|
||||
len -= 16;
|
||||
break;
|
||||
|
||||
case 15: *dp++ = *sp++;
|
||||
case 14: *dp++ = *sp++;
|
||||
case 13: *dp++ = *sp++;
|
||||
case 12: *dp++ = *sp++;
|
||||
case 11: *dp++ = *sp++;
|
||||
case 10: *dp++ = *sp++;
|
||||
case 9: *dp++ = *sp++;
|
||||
case 8: *dp++ = *sp++;
|
||||
|
||||
case 7: *dp++ = *sp++;
|
||||
case 6: *dp++ = *sp++;
|
||||
case 5: *dp++ = *sp++;
|
||||
case 4: *dp++ = *sp++;
|
||||
case 3: *dp++ = *sp++;
|
||||
case 2: *dp++ = *sp++;
|
||||
case 1: *dp++ = *sp++;
|
||||
len = 0;
|
||||
break;
|
||||
}
|
||||
} /* end while */
|
||||
|
||||
} else {
|
||||
/*
|
||||
* This section is used to copy backwards, to handle any
|
||||
* overlap. The alignment requires (tps&wmask) bytes to
|
||||
* align.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* go to end of the memory to copy
|
||||
*/
|
||||
sp += len;
|
||||
dp += len;
|
||||
|
||||
while (len != 0) {
|
||||
|
||||
switch (len) {
|
||||
/*
|
||||
* Here we do blocks of 8. Once the remaining count
|
||||
* drops below 8, take the fast track to finish up.
|
||||
*/
|
||||
default:
|
||||
*--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp;
|
||||
*--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp;
|
||||
*--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp;
|
||||
*--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp;
|
||||
len -= 16;
|
||||
break;
|
||||
|
||||
case 15: *--dp = *--sp;
|
||||
case 14: *--dp = *--sp;
|
||||
case 13: *--dp = *--sp;
|
||||
case 12: *--dp = *--sp;
|
||||
case 11: *--dp = *--sp;
|
||||
case 10: *--dp = *--sp;
|
||||
case 9: *--dp = *--sp;
|
||||
case 8: *--dp = *--sp;
|
||||
|
||||
case 7: *--dp = *--sp;
|
||||
case 6: *--dp = *--sp;
|
||||
case 5: *--dp = *--sp;
|
||||
case 4: *--dp = *--sp;
|
||||
case 3: *--dp = *--sp;
|
||||
case 2: *--dp = *--sp;
|
||||
case 1: *--dp = *--sp;
|
||||
len = 0;
|
||||
break;
|
||||
}
|
||||
} /* end while */
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* NAME
|
||||
* mem_prim_move16 - Move (handles overlap) memory
|
||||
*
|
||||
* SYNOPSIS
|
||||
* #include "mem_primitives_lib.h"
|
||||
* void
|
||||
* mem_prim_move16(void *dest, const void *src, uint32_t len)
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Moves at most len uint16_ts from sp to dp.
|
||||
* The destination may overlap with source.
|
||||
*
|
||||
* INPUT PARAMETERS
|
||||
* dp - pointer to the memory that will be replaced by sp.
|
||||
*
|
||||
* sp - pointer to the memory that will be copied
|
||||
* to dp
|
||||
*
|
||||
* len - maximum number uint16_t of sp that can be copied
|
||||
*
|
||||
* OUTPUT PARAMETERS
|
||||
* dp - is updated
|
||||
*
|
||||
* RETURN VALUE
|
||||
* none
|
||||
*
|
||||
*/
|
||||
void
|
||||
mem_prim_move16 (uint16_t *dp, const uint16_t *sp, uint32_t len)
|
||||
{
|
||||
|
||||
/*
|
||||
* Determine if we need to copy forward or backward (overlap)
|
||||
*/
|
||||
if (dp < sp) {
|
||||
/*
|
||||
* Copy forward.
|
||||
*/
|
||||
|
||||
while (len != 0) {
|
||||
|
||||
switch (len) {
|
||||
/*
|
||||
* Here we do blocks of 8. Once the remaining count
|
||||
* drops below 8, take the fast track to finish up.
|
||||
*/
|
||||
default:
|
||||
*dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++;
|
||||
*dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++;
|
||||
*dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++;
|
||||
*dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++;
|
||||
len -= 16;
|
||||
break;
|
||||
|
||||
case 15: *dp++ = *sp++;
|
||||
case 14: *dp++ = *sp++;
|
||||
case 13: *dp++ = *sp++;
|
||||
case 12: *dp++ = *sp++;
|
||||
case 11: *dp++ = *sp++;
|
||||
case 10: *dp++ = *sp++;
|
||||
case 9: *dp++ = *sp++;
|
||||
case 8: *dp++ = *sp++;
|
||||
|
||||
case 7: *dp++ = *sp++;
|
||||
case 6: *dp++ = *sp++;
|
||||
case 5: *dp++ = *sp++;
|
||||
case 4: *dp++ = *sp++;
|
||||
case 3: *dp++ = *sp++;
|
||||
case 2: *dp++ = *sp++;
|
||||
case 1: *dp++ = *sp++;
|
||||
len = 0;
|
||||
break;
|
||||
}
|
||||
} /* end while */
|
||||
|
||||
} else {
|
||||
/*
|
||||
* This section is used to copy backwards, to handle any
|
||||
* overlap. The alignment requires (tps&wmask) bytes to
|
||||
* align.
|
||||
*/
|
||||
|
||||
/*
|
||||
* go to end of the memory to copy
|
||||
*/
|
||||
sp += len;
|
||||
dp += len;
|
||||
|
||||
while (len != 0) {
|
||||
|
||||
switch (len) {
|
||||
/*
|
||||
* Here we do blocks of 8. Once the remaining count
|
||||
* drops below 8, take the fast track to finish up.
|
||||
*/
|
||||
default:
|
||||
*--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp;
|
||||
*--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp;
|
||||
*--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp;
|
||||
*--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp;
|
||||
len -= 16;
|
||||
break;
|
||||
|
||||
case 15: *--dp = *--sp;
|
||||
case 14: *--dp = *--sp;
|
||||
case 13: *--dp = *--sp;
|
||||
case 12: *--dp = *--sp;
|
||||
case 11: *--dp = *--sp;
|
||||
case 10: *--dp = *--sp;
|
||||
case 9: *--dp = *--sp;
|
||||
case 8: *--dp = *--sp;
|
||||
|
||||
case 7: *--dp = *--sp;
|
||||
case 6: *--dp = *--sp;
|
||||
case 5: *--dp = *--sp;
|
||||
case 4: *--dp = *--sp;
|
||||
case 3: *--dp = *--sp;
|
||||
case 2: *--dp = *--sp;
|
||||
case 1: *--dp = *--sp;
|
||||
len = 0;
|
||||
break;
|
||||
}
|
||||
} /* end while */
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* NAME
|
||||
* mem_prim_move32 - Move (handles overlap) memory
|
||||
*
|
||||
* SYNOPSIS
|
||||
* #include "mem_primitives_lib.h"
|
||||
* void
|
||||
* mem_prim_move32(void *dest, const void *src, uint32_t len)
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Moves at most len uint32_ts from sp to dp.
|
||||
* The destination may overlap with source.
|
||||
*
|
||||
* INPUT PARAMETERS
|
||||
* dp - pointer to the memory that will be replaced by sp.
|
||||
*
|
||||
* sp - pointer to the memory that will be copied
|
||||
* to dp
|
||||
*
|
||||
* len - maximum number uint32_t of sp that can be copied
|
||||
*
|
||||
* OUTPUT PARAMETERS
|
||||
* dp - is updated
|
||||
*
|
||||
* RETURN VALUE
|
||||
* none
|
||||
*
|
||||
*/
|
||||
void
|
||||
mem_prim_move32 (uint32_t *dp, const uint32_t *sp, uint32_t len)
|
||||
{
|
||||
|
||||
/*
|
||||
* Determine if we need to copy forward or backward (overlap)
|
||||
*/
|
||||
if (dp < sp) {
|
||||
/*
|
||||
* Copy forward.
|
||||
*/
|
||||
|
||||
while (len != 0) {
|
||||
|
||||
switch (len) {
|
||||
/*
|
||||
* Here we do blocks of 8. Once the remaining count
|
||||
* drops below 8, take the fast track to finish up.
|
||||
*/
|
||||
default:
|
||||
*dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++;
|
||||
*dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++;
|
||||
*dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++;
|
||||
*dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp++;
|
||||
len -= 16;
|
||||
break;
|
||||
|
||||
case 15: *dp++ = *sp++;
|
||||
case 14: *dp++ = *sp++;
|
||||
case 13: *dp++ = *sp++;
|
||||
case 12: *dp++ = *sp++;
|
||||
case 11: *dp++ = *sp++;
|
||||
case 10: *dp++ = *sp++;
|
||||
case 9: *dp++ = *sp++;
|
||||
case 8: *dp++ = *sp++;
|
||||
|
||||
case 7: *dp++ = *sp++;
|
||||
case 6: *dp++ = *sp++;
|
||||
case 5: *dp++ = *sp++;
|
||||
case 4: *dp++ = *sp++;
|
||||
case 3: *dp++ = *sp++;
|
||||
case 2: *dp++ = *sp++;
|
||||
case 1: *dp++ = *sp++;
|
||||
len = 0;
|
||||
break;
|
||||
}
|
||||
} /* end while */
|
||||
|
||||
} else {
|
||||
/*
|
||||
* This section is used to copy backwards, to handle any
|
||||
* overlap.
|
||||
*/
|
||||
|
||||
/*
|
||||
* go to end of the memory to copy
|
||||
*/
|
||||
sp += len;
|
||||
dp += len;
|
||||
|
||||
while (len != 0) {
|
||||
|
||||
switch (len) {
|
||||
/*
|
||||
* Here we do blocks of 8. Once the remaining count
|
||||
* drops below 8, take the fast track to finish up.
|
||||
*/
|
||||
default:
|
||||
*--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp;
|
||||
*--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp;
|
||||
*--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp;
|
||||
*--dp = *--sp; *--dp = *--sp; *--dp = *--sp; *--dp = *--sp;
|
||||
len -= 16;
|
||||
break;
|
||||
|
||||
case 15: *--dp = *--sp;
|
||||
case 14: *--dp = *--sp;
|
||||
case 13: *--dp = *--sp;
|
||||
case 12: *--dp = *--sp;
|
||||
case 11: *--dp = *--sp;
|
||||
case 10: *--dp = *--sp;
|
||||
case 9: *--dp = *--sp;
|
||||
case 8: *--dp = *--sp;
|
||||
|
||||
case 7: *--dp = *--sp;
|
||||
case 6: *--dp = *--sp;
|
||||
case 5: *--dp = *--sp;
|
||||
case 4: *--dp = *--sp;
|
||||
case 3: *--dp = *--sp;
|
||||
case 2: *--dp = *--sp;
|
||||
case 1: *--dp = *--sp;
|
||||
len = 0;
|
||||
break;
|
||||
}
|
||||
} /* end while */
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
74
casadm/safeclib/mem_primitives_lib.h
Normal file
74
casadm/safeclib/mem_primitives_lib.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/*------------------------------------------------------------------
|
||||
* mem_primitives_lib.h - Unguarded Memory Copy Routines
|
||||
*
|
||||
* October 2008, Bo Berry
|
||||
*
|
||||
* Copyright (c) 2008-2011 by Cisco Systems, Inc
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef __MEM_PRIMITIVES_LIB_H__
|
||||
#define __MEM_PRIMITIVES_LIB_H__
|
||||
|
||||
#include "safeclib_private.h"
|
||||
|
||||
/*
|
||||
* These are prototypes for _unguarded_ memory routines. The caller must
|
||||
* validate all parameters prior to invocation. Useful for diagnostics
|
||||
* and system initialization processing.
|
||||
*/
|
||||
|
||||
/* moves (handles overlap) memory */
|
||||
extern void
|
||||
mem_prim_move(void *dest, const void *src, uint32_t length);
|
||||
|
||||
|
||||
/* uint8_t moves (handles overlap) memory */
|
||||
extern void
|
||||
mem_prim_move8(uint8_t *dest, const uint8_t *src, uint32_t length);
|
||||
|
||||
/* uint16_t moves (handles overlap) memory */
|
||||
extern void
|
||||
mem_prim_move16(uint16_t *dest, const uint16_t *src, uint32_t length);
|
||||
|
||||
/* uint32_t moves (handles overlap) memory */
|
||||
extern void
|
||||
mem_prim_move32(uint32_t *dest, const uint32_t *src, uint32_t length);
|
||||
|
||||
|
||||
/* set bytes */
|
||||
extern void
|
||||
mem_prim_set(void *dest, uint32_t dmax, uint8_t value);
|
||||
|
||||
/* set uint16_ts */
|
||||
extern void
|
||||
mem_prim_set16(uint16_t *dest, uint32_t dmax, uint16_t value);
|
||||
|
||||
/* set uint32_ts */
|
||||
extern void
|
||||
mem_prim_set32(uint32_t *dest, uint32_t dmax, uint32_t value);
|
||||
|
||||
|
||||
#endif /* __MEM_PRIMITIVES_LIB_H__ */
|
157
casadm/safeclib/memcpy_s.c
Normal file
157
casadm/safeclib/memcpy_s.c
Normal file
@@ -0,0 +1,157 @@
|
||||
/*------------------------------------------------------------------
|
||||
* memcpy_s
|
||||
*
|
||||
* October 2008, Bo Berry
|
||||
*
|
||||
* Copyright (c) 2008-2011 Cisco Systems
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "safeclib_private.h"
|
||||
#include "safe_mem_constraint.h"
|
||||
#include "mem_primitives_lib.h"
|
||||
#include "safe_mem_lib.h"
|
||||
|
||||
|
||||
/**
|
||||
* NAME
|
||||
* memcpy_s
|
||||
*
|
||||
* SYNOPSIS
|
||||
* #include "safe_mem_lib.h"
|
||||
* errno_t
|
||||
* memcpy_s(void *dest, rsize_t dmax, const void *src, rsize_t smax)
|
||||
*
|
||||
* DESCRIPTION
|
||||
* This function copies at most smax bytes from src to dest, up to
|
||||
* dmax.
|
||||
*
|
||||
* SPECIFIED IN
|
||||
* ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments
|
||||
* and system software interfaces, Extensions to the C Library,
|
||||
* Part I: Bounds-checking interfaces
|
||||
*
|
||||
* INPUT PARAMETERS
|
||||
* dest pointer to memory that will be replaced by src.
|
||||
*
|
||||
* dmax maximum length of the resulting dest
|
||||
*
|
||||
* src pointer to the memory that will be copied to dest
|
||||
*
|
||||
* smax maximum number bytes of src to copy
|
||||
*
|
||||
* OUTPUT PARAMETERS
|
||||
* dest is updated
|
||||
*
|
||||
* RUNTIME CONSTRAINTS
|
||||
* Neither dest nor src shall be a null pointer.
|
||||
* Neither dmax nor smax shall be zero.
|
||||
* dmax shall not be greater than RSIZE_MAX_MEM.
|
||||
* smax shall not be greater than dmax.
|
||||
* Copying shall not take place between regions that overlap.
|
||||
* If there is a runtime-constraint violation, the memcpy_s function
|
||||
* stores zeros in the first dmax bytes of the region pointed to
|
||||
* by dest if dest is not a null pointer and smax is valid.
|
||||
*
|
||||
* RETURN VALUE
|
||||
* EOK successful operation
|
||||
* ESNULLP NULL pointer
|
||||
* ESZEROL zero length
|
||||
* ESLEMAX length exceeds max limit
|
||||
* ESOVRLP source memory overlaps destination
|
||||
*
|
||||
* ALSO SEE
|
||||
* memcpy16_s(), memcpy32_s(), memmove_s(), memmove16_s(),
|
||||
* memmove32_s()
|
||||
*
|
||||
*/
|
||||
errno_t
|
||||
memcpy_s (void *dest, rsize_t dmax, const void *src, rsize_t smax)
|
||||
{
|
||||
uint8_t *dp;
|
||||
const uint8_t *sp;
|
||||
|
||||
dp = dest;
|
||||
sp = src;
|
||||
|
||||
if (dp == NULL) {
|
||||
invoke_safe_mem_constraint_handler("memcpy_s: dest is NULL",
|
||||
NULL, ESNULLP);
|
||||
return RCNEGATE(ESNULLP);
|
||||
}
|
||||
|
||||
if (dmax == 0) {
|
||||
invoke_safe_mem_constraint_handler("memcpy_s: dmax is 0",
|
||||
NULL, ESZEROL);
|
||||
return RCNEGATE(ESZEROL);
|
||||
}
|
||||
|
||||
if (dmax > RSIZE_MAX_MEM) {
|
||||
invoke_safe_mem_constraint_handler("memcpy_s: dmax exceeds max",
|
||||
NULL, ESLEMAX);
|
||||
return RCNEGATE(ESLEMAX);
|
||||
}
|
||||
|
||||
if (smax == 0) {
|
||||
mem_prim_set(dp, dmax, 0);
|
||||
invoke_safe_mem_constraint_handler("memcpy_s: smax is 0",
|
||||
NULL, ESZEROL);
|
||||
return RCNEGATE(ESZEROL);
|
||||
}
|
||||
|
||||
if (smax > dmax) {
|
||||
mem_prim_set(dp, dmax, 0);
|
||||
invoke_safe_mem_constraint_handler("memcpy_s: smax exceeds dmax",
|
||||
NULL, ESLEMAX);
|
||||
return RCNEGATE(ESLEMAX);
|
||||
}
|
||||
|
||||
if (sp == NULL) {
|
||||
mem_prim_set(dp, dmax, 0);
|
||||
invoke_safe_mem_constraint_handler("memcpy_s: src is NULL",
|
||||
NULL, ESNULLP);
|
||||
return RCNEGATE(ESNULLP);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* overlap is undefined behavior, do not allow
|
||||
*/
|
||||
if( ((dp > sp) && (dp < (sp+smax))) ||
|
||||
((sp > dp) && (sp < (dp+dmax))) ) {
|
||||
mem_prim_set(dp, dmax, 0);
|
||||
invoke_safe_mem_constraint_handler("memcpy_s: overlap undefined",
|
||||
NULL, ESOVRLP);
|
||||
return RCNEGATE(ESOVRLP);
|
||||
}
|
||||
|
||||
/*
|
||||
* now perform the copy
|
||||
*/
|
||||
mem_prim_move(dp, sp, smax);
|
||||
|
||||
return RCNEGATE(EOK);
|
||||
}
|
||||
EXPORT_SYMBOL(memcpy_s);
|
148
casadm/safeclib/memmove_s.c
Normal file
148
casadm/safeclib/memmove_s.c
Normal file
@@ -0,0 +1,148 @@
|
||||
/*------------------------------------------------------------------
|
||||
* memmove_s.c
|
||||
*
|
||||
* October 2008, Bo Berry
|
||||
*
|
||||
* Copyright (c) 2008-2011 Cisco Systems
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "safeclib_private.h"
|
||||
#include "safe_mem_constraint.h"
|
||||
#include "mem_primitives_lib.h"
|
||||
#include "safe_mem_lib.h"
|
||||
|
||||
/**
|
||||
* NAME
|
||||
* memmove_s
|
||||
*
|
||||
* SYNOPSIS
|
||||
* #include "safe_mem_lib.h"
|
||||
* errno_t
|
||||
* memmove_s(void *dest, rsize_t dmax,
|
||||
* const void *src, rsize_t smax)
|
||||
*
|
||||
* DESCRIPTION
|
||||
* The memmove_s function copies smax bytes from the region pointed
|
||||
* to by src into the region pointed to by dest. This copying takes place
|
||||
* as if the smax bytes from the region pointed to by src are first copied
|
||||
* into a temporary array of smax bytes that does not overlap the region
|
||||
* pointed to by dest or src, and then the smax bytes from the temporary
|
||||
* array are copied into the object region to by dest.
|
||||
*
|
||||
* SPECIFIED IN
|
||||
* ISO/IEC TR 24731, Programming languages, environments
|
||||
* and system software interfaces, Extensions to the C Library,
|
||||
* Part I: Bounds-checking interfaces
|
||||
*
|
||||
* INPUT PARAMETERS
|
||||
* dest pointer to the memory that will be replaced by src.
|
||||
*
|
||||
* dmax maximum length of the resulting dest, in bytes
|
||||
*
|
||||
* src pointer to the memory that will be copied
|
||||
* to dest
|
||||
*
|
||||
* smax maximum number bytes of src that can be copied
|
||||
*
|
||||
* OUTPUT PARAMETERS
|
||||
* dest is updated
|
||||
*
|
||||
* RUNTIME CONSTRAINTS
|
||||
* Neither dest nor src shall be a null pointer.
|
||||
* Neither dmax nor smax shall be 0.
|
||||
* dmax shall not be greater than RSIZE_MAX_MEM.
|
||||
* smax shall not be greater than dmax.
|
||||
* If there is a runtime-constraint violation, the memmove_s function
|
||||
* stores zeros in the first dmax characters of the regionpointed to
|
||||
* by dest if dest is not a null pointer and dmax is not greater
|
||||
* than RSIZE_MAX_MEM.
|
||||
*
|
||||
* RETURN VALUE
|
||||
* EOK successful operation
|
||||
* ESNULLP NULL pointer
|
||||
* ESZEROL zero length
|
||||
* ESLEMAX length exceeds max limit
|
||||
*
|
||||
* ALSO SEE
|
||||
* memmove16_s(), memmove32_s(), memcpy_s(), memcpy16_s() memcpy32_s()
|
||||
*
|
||||
*/
|
||||
errno_t
|
||||
memmove_s (void *dest, rsize_t dmax, const void *src, rsize_t smax)
|
||||
{
|
||||
uint8_t *dp;
|
||||
const uint8_t *sp;
|
||||
|
||||
dp= dest;
|
||||
sp = src;
|
||||
|
||||
if (dp == NULL) {
|
||||
invoke_safe_mem_constraint_handler("memmove_s: dest is null",
|
||||
NULL, ESNULLP);
|
||||
return (RCNEGATE(ESNULLP));
|
||||
}
|
||||
|
||||
if (dmax == 0) {
|
||||
invoke_safe_mem_constraint_handler("memmove_s: dmax is 0",
|
||||
NULL, ESZEROL);
|
||||
return (RCNEGATE(ESZEROL));
|
||||
}
|
||||
|
||||
if (dmax > RSIZE_MAX_MEM) {
|
||||
invoke_safe_mem_constraint_handler("memmove_s: dmax exceeds max",
|
||||
NULL, ESLEMAX);
|
||||
return (RCNEGATE(ESLEMAX));
|
||||
}
|
||||
|
||||
if (smax == 0) {
|
||||
mem_prim_set(dp, dmax, 0);
|
||||
invoke_safe_mem_constraint_handler("memmove_s: smax is 0",
|
||||
NULL, ESZEROL);
|
||||
return (RCNEGATE(ESZEROL));
|
||||
}
|
||||
|
||||
if (smax > dmax) {
|
||||
mem_prim_set(dp, dmax, 0);
|
||||
invoke_safe_mem_constraint_handler("memmove_s: smax exceeds max",
|
||||
NULL, ESLEMAX);
|
||||
return (RCNEGATE(ESLEMAX));
|
||||
}
|
||||
|
||||
if (sp == NULL) {
|
||||
mem_prim_set(dp, dmax, 0);
|
||||
invoke_safe_mem_constraint_handler("memmove_s: src is null",
|
||||
NULL, ESNULLP);
|
||||
return (RCNEGATE(ESNULLP));
|
||||
}
|
||||
|
||||
/*
|
||||
* now perform the copy
|
||||
*/
|
||||
mem_prim_move(dp, sp, smax);
|
||||
|
||||
return (RCNEGATE(EOK));
|
||||
}
|
||||
EXPORT_SYMBOL(memmove_s);
|
105
casadm/safeclib/memset_s.c
Normal file
105
casadm/safeclib/memset_s.c
Normal file
@@ -0,0 +1,105 @@
|
||||
/*------------------------------------------------------------------
|
||||
* memset_s
|
||||
*
|
||||
* October 2008, Bo Berry
|
||||
*
|
||||
* Copyright (c) 2008-2011 Cisco Systems
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "safeclib_private.h"
|
||||
#include "safe_mem_constraint.h"
|
||||
#include "mem_primitives_lib.h"
|
||||
#include "safe_mem_lib.h"
|
||||
|
||||
|
||||
/**
|
||||
* NAME
|
||||
* memset_s
|
||||
*
|
||||
* SYNOPSIS
|
||||
* #include "safe_mem_lib.h"
|
||||
* errno_t
|
||||
* memset_s(void *dest, rsize_t len, uint8_t value)
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Sets len bytes starting at dest to the specified value.
|
||||
*
|
||||
* SPECIFIED IN
|
||||
* ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments
|
||||
* and system software interfaces, Extensions to the C Library,
|
||||
* Part I: Bounds-checking interfaces
|
||||
*
|
||||
* INPUT PARAMETERS
|
||||
* dest pointer to memory that will be set to the value
|
||||
*
|
||||
* len number of bytes to be set
|
||||
*
|
||||
* value byte value
|
||||
*
|
||||
* OUTPUT PARAMETERS
|
||||
* dest is updated
|
||||
*
|
||||
* RUNTIME CONSTRAINTS
|
||||
* dest shall not be a null pointer.
|
||||
* len shall not be 0 nor greater than RSIZE_MAX_MEM.
|
||||
* If there is a runtime constraint, the operation is not performed.
|
||||
*
|
||||
* RETURN VALUE
|
||||
* EOK successful operation
|
||||
* ESNULLP NULL pointer
|
||||
* ESZEROL zero length
|
||||
* ESLEMAX length exceeds max limit
|
||||
*
|
||||
* ALSO SEE
|
||||
* memset16_s(), memset32_s()
|
||||
*
|
||||
*/
|
||||
errno_t
|
||||
memset_s (void *dest, rsize_t len, uint8_t value)
|
||||
{
|
||||
if (dest == NULL) {
|
||||
invoke_safe_mem_constraint_handler("memset_s: dest is null",
|
||||
NULL, ESNULLP);
|
||||
return (RCNEGATE(ESNULLP));
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
invoke_safe_mem_constraint_handler("memset_s: len is 0",
|
||||
NULL, ESZEROL);
|
||||
return (RCNEGATE(ESZEROL));
|
||||
}
|
||||
|
||||
if (len > RSIZE_MAX_MEM) {
|
||||
invoke_safe_mem_constraint_handler("memset_s: len exceeds max",
|
||||
NULL, ESLEMAX);
|
||||
return (RCNEGATE(ESLEMAX));
|
||||
}
|
||||
|
||||
mem_prim_set(dest, len, value);
|
||||
|
||||
return (RCNEGATE(EOK));
|
||||
}
|
||||
EXPORT_SYMBOL(memset_s);
|
61
casadm/safeclib/safe_lib.h
Normal file
61
casadm/safeclib/safe_lib.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*------------------------------------------------------------------
|
||||
* safe_lib.h -- Safe C Library
|
||||
*
|
||||
* October 2008, Bo Berry
|
||||
* Modified 2012, Jonathan Toppins <jtoppins@users.sourceforge.net>
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Cisco Systems, Inc
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef __SAFE_LIB_H__
|
||||
#define __SAFE_LIB_H__
|
||||
|
||||
#include "safe_types.h"
|
||||
#include "safe_lib_errno.h"
|
||||
|
||||
/* C11 appendix K types - specific for bounds checking */
|
||||
typedef size_t rsize_t;
|
||||
|
||||
/*
|
||||
* We depart from the standard and allow memory and string operations to
|
||||
* have different max sizes. See the respective safe_mem_lib.h or
|
||||
* safe_str_lib.h files.
|
||||
*/
|
||||
/* #define RSIZE_MAX (~(rsize_t)0) - leave here for completeness */
|
||||
|
||||
typedef void (*constraint_handler_t) (const char * /* msg */,
|
||||
void * /* ptr */,
|
||||
errno_t /* error */);
|
||||
|
||||
extern void abort_handler_s(const char *msg, void *ptr, errno_t error);
|
||||
extern void ignore_handler_s(const char *msg, void *ptr, errno_t error);
|
||||
|
||||
#define sl_default_handler ignore_handler_s
|
||||
|
||||
#include "safe_mem_lib.h"
|
||||
#include "safe_str_lib.h"
|
||||
|
||||
#endif /* __SAFE_LIB_H__ */
|
91
casadm/safeclib/safe_lib_errno.h
Normal file
91
casadm/safeclib/safe_lib_errno.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/*------------------------------------------------------------------
|
||||
* safe_lib_errno.h -- Safe C Lib Error codes
|
||||
*
|
||||
* October 2008, Bo Berry
|
||||
* Modified 2012, Jonathan Toppins <jtoppins@users.sourceforge.net>
|
||||
*
|
||||
* Copyright (c) 2008-2013 by Cisco Systems, Inc
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef __SAFE_LIB_ERRNO_H__
|
||||
#define __SAFE_LIB_ERRNO_H__
|
||||
|
||||
#ifdef __KERNEL__
|
||||
# include <linux/errno.h>
|
||||
#else
|
||||
#include <errno.h>
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
/*
|
||||
* Safe Lib specific errno codes. These can be added to the errno.h file
|
||||
* if desired.
|
||||
*/
|
||||
#ifndef ESNULLP
|
||||
#define ESNULLP ( 400 ) /* null ptr */
|
||||
#endif
|
||||
|
||||
#ifndef ESZEROL
|
||||
#define ESZEROL ( 401 ) /* length is zero */
|
||||
#endif
|
||||
|
||||
#ifndef ESLEMIN
|
||||
#define ESLEMIN ( 402 ) /* length is below min */
|
||||
#endif
|
||||
|
||||
#ifndef ESLEMAX
|
||||
#define ESLEMAX ( 403 ) /* length exceeds max */
|
||||
#endif
|
||||
|
||||
#ifndef ESOVRLP
|
||||
#define ESOVRLP ( 404 ) /* overlap undefined */
|
||||
#endif
|
||||
|
||||
#ifndef ESEMPTY
|
||||
#define ESEMPTY ( 405 ) /* empty string */
|
||||
#endif
|
||||
|
||||
#ifndef ESNOSPC
|
||||
#define ESNOSPC ( 406 ) /* not enough space for s2 */
|
||||
#endif
|
||||
|
||||
#ifndef ESUNTERM
|
||||
#define ESUNTERM ( 407 ) /* unterminated string */
|
||||
#endif
|
||||
|
||||
#ifndef ESNODIFF
|
||||
#define ESNODIFF ( 408 ) /* no difference */
|
||||
#endif
|
||||
|
||||
#ifndef ESNOTFND
|
||||
#define ESNOTFND ( 409 ) /* not found */
|
||||
#endif
|
||||
|
||||
/* EOK may or may not be defined in errno.h */
|
||||
#ifndef EOK
|
||||
#define EOK ( 0 )
|
||||
#endif
|
||||
|
||||
#endif /* __SAFE_LIB_ERRNO_H__ */
|
142
casadm/safeclib/safe_mem_constraint.c
Normal file
142
casadm/safeclib/safe_mem_constraint.c
Normal file
@@ -0,0 +1,142 @@
|
||||
/*------------------------------------------------------------------
|
||||
* safe_mem_constraint.c
|
||||
*
|
||||
* October 2008, Bo Berry
|
||||
* 2012, Jonathan Toppins <jtoppins@users.sourceforge.net>
|
||||
*
|
||||
* Copyright (c) 2008-2012 Cisco Systems
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "safeclib_private.h"
|
||||
#include "safe_mem_constraint.h"
|
||||
#include "safe_mem_lib.h"
|
||||
|
||||
|
||||
static constraint_handler_t mem_handler = NULL;
|
||||
|
||||
|
||||
/**
|
||||
* NAME
|
||||
* set_mem_constraint_handler_s
|
||||
*
|
||||
* SYNOPSIS
|
||||
* #include "safe_mem_lib.h"
|
||||
* constraint_handler_t
|
||||
* set_mem_constraint_handler_straint_handler_t handler)
|
||||
*
|
||||
* DESCRIPTION
|
||||
* The set_mem_constraint_handler_s function sets the runtime-constraint
|
||||
* handler to be handler. The runtime-constraint handler is the function to
|
||||
* be called when a library function detects a runtime-constraint
|
||||
* order:
|
||||
* 1. A pointer to a character string describing the
|
||||
* runtime-constraint violation.
|
||||
* 2. A null pointer or a pointer to an implementation defined
|
||||
* object.
|
||||
* 3. If the function calling the handler has a return type declared
|
||||
* as errno_t, the return value of the function is passed.
|
||||
* Otherwise, a positive value of type errno_t is passed.
|
||||
* The implementation has a default constraint handler that is used if no
|
||||
* calls to the set_constraint_handler_s function have been made. The
|
||||
* behavior of the default handler is implementation-defined, and it may
|
||||
* cause the program to exit or abort. If the handler argument to
|
||||
* set_constraint_handler_s is a null pointer, the implementation default
|
||||
* handler becomes the current constraint handler.
|
||||
*
|
||||
* SPECIFIED IN
|
||||
* ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments
|
||||
* and system software interfaces, Extensions to the C Library,
|
||||
* Part I: Bounds-checking interfaces
|
||||
*
|
||||
* INPUT PARAMETERS
|
||||
* *msg Pointer to the message describing the error
|
||||
*
|
||||
* *ptr Pointer to aassociated data. Can be NULL.
|
||||
*
|
||||
* error The error code encountered.
|
||||
*
|
||||
* OUTPUT PARAMETERS
|
||||
* none
|
||||
*
|
||||
* RETURN VALUE
|
||||
* none
|
||||
*
|
||||
* ALSO SEE
|
||||
* set_str_constraint_handler_s()
|
||||
*/
|
||||
constraint_handler_t
|
||||
set_mem_constraint_handler_s (constraint_handler_t handler)
|
||||
{
|
||||
constraint_handler_t prev_handler = mem_handler;
|
||||
if (NULL == handler) {
|
||||
mem_handler = sl_default_handler;
|
||||
} else {
|
||||
mem_handler = handler;
|
||||
}
|
||||
return prev_handler;
|
||||
}
|
||||
EXPORT_SYMBOL(set_mem_constraint_handler_s);
|
||||
|
||||
|
||||
/**
|
||||
* NAME
|
||||
* invoke_safe_mem_constraint_handler
|
||||
*
|
||||
* SYNOPSIS
|
||||
* #include "safe_mem_constraint.h"
|
||||
* void
|
||||
* invoke_safe_mem_constraint_handler(const char *msg,
|
||||
* void *ptr,
|
||||
* errno_t error)
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Invokes the currently set constraint handler or the default.
|
||||
*
|
||||
* INPUT PARAMETERS
|
||||
* *msg Pointer to the message describing the error
|
||||
*
|
||||
* *ptr Pointer to aassociated data. Can be NULL.
|
||||
*
|
||||
* error The error code encountered.
|
||||
*
|
||||
* OUTPUT PARAMETERS
|
||||
* none
|
||||
*
|
||||
* RETURN VALUE
|
||||
* none
|
||||
*
|
||||
*/
|
||||
void
|
||||
invoke_safe_mem_constraint_handler (const char *msg,
|
||||
void *ptr,
|
||||
errno_t error)
|
||||
{
|
||||
if (NULL != mem_handler) {
|
||||
mem_handler(msg, ptr, error);
|
||||
} else {
|
||||
sl_default_handler(msg, ptr, error);
|
||||
}
|
||||
}
|
46
casadm/safeclib/safe_mem_constraint.h
Normal file
46
casadm/safeclib/safe_mem_constraint.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*------------------------------------------------------------------
|
||||
* safe_mem_constraint.h
|
||||
*
|
||||
* October 2008, Bo Berry
|
||||
*
|
||||
* Copyright (c) 2008, 2009 by Cisco Systems, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef __SAFE_MEM_CONSTRAINT_H__
|
||||
#define __SAFE_MEM_CONSTRAINT_H__
|
||||
|
||||
#include "safeclib_private.h"
|
||||
|
||||
/*
|
||||
* Function used by the libraries to invoke the registered
|
||||
* runtime-constraint handler. Always needed.
|
||||
*/
|
||||
extern void invoke_safe_mem_constraint_handler(
|
||||
const char *msg,
|
||||
void *ptr,
|
||||
errno_t error);
|
||||
|
||||
#endif /* __SAFE_MEM_CONSTRAINT_H__ */
|
57
casadm/safeclib/safe_mem_lib.h
Normal file
57
casadm/safeclib/safe_mem_lib.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*------------------------------------------------------------------
|
||||
* safe_mem_lib.h -- Safe C Library Memory APIs
|
||||
*
|
||||
* October 2008, Bo Berry
|
||||
* Modified 2012, Jonathan Toppins <jtoppins@users.sourceforge.net>
|
||||
*
|
||||
* Copyright (c) 2008-2012 by Cisco Systems, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef __SAFE_MEM_LIB_H__
|
||||
#define __SAFE_MEM_LIB_H__
|
||||
|
||||
#include "safe_lib.h"
|
||||
|
||||
#define RSIZE_MAX_MEM ( 256UL << 20 ) /* 256MB */
|
||||
#define RSIZE_MAX_MEM16 ( RSIZE_MAX_MEM/2 )
|
||||
#define RSIZE_MAX_MEM32 ( RSIZE_MAX_MEM/4 )
|
||||
|
||||
/* set memory constraint handler */
|
||||
extern constraint_handler_t
|
||||
set_mem_constraint_handler_s(constraint_handler_t handler);
|
||||
|
||||
/* copy memory */
|
||||
extern errno_t memcpy_s(void *dest, rsize_t dmax,
|
||||
const void *src, rsize_t slen);
|
||||
|
||||
/* set bytes */
|
||||
extern errno_t memset_s(void *dest, rsize_t dmax, uint8_t value);
|
||||
|
||||
/* move memory, including overlapping memory */
|
||||
extern errno_t memmove_s(void *dest, rsize_t dmax,
|
||||
const void *src, rsize_t slen);
|
||||
|
||||
#endif /* __SAFE_MEM_LIB_H__ */
|
146
casadm/safeclib/safe_str_constraint.c
Normal file
146
casadm/safeclib/safe_str_constraint.c
Normal file
@@ -0,0 +1,146 @@
|
||||
/*------------------------------------------------------------------
|
||||
* safe_str_constraint.c
|
||||
*
|
||||
* October 2008, Bo Berry
|
||||
* 2012, Jonathan Toppins <jtoppins@users.sourceforge.net>
|
||||
*
|
||||
* Copyright (c) 2008, 2009, 2012 Cisco Systems
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "safeclib_private.h"
|
||||
#include "safe_str_constraint.h"
|
||||
#include "safe_str_lib.h"
|
||||
|
||||
|
||||
static constraint_handler_t str_handler = NULL;
|
||||
|
||||
|
||||
/**
|
||||
* NAME
|
||||
* set_str_constraint_handler_s
|
||||
*
|
||||
* SYNOPSIS
|
||||
* #include "safe_str_lib.h"
|
||||
* constraint_handler_t
|
||||
* set_str_constraint_handler_s(constraint_handler_t handler)
|
||||
*
|
||||
* DESCRIPTION
|
||||
* The set_str_constraint_handler_s function sets the runtime-constraint
|
||||
* handler to be handler. The runtime-constraint handler is the function to
|
||||
* be called when a library function detects a runtime-constraint
|
||||
* violation. Only the most recent handler registered with
|
||||
* set_str_constraint_handler_s is called when a runtime-constraint
|
||||
* violation occurs.
|
||||
* When the handler is called, it is passed the following arguments in
|
||||
* the following order:
|
||||
* 1. A pointer to a character string describing the
|
||||
* runtime-constraint violation.
|
||||
* 2. A null pointer or a pointer to an implementation defined
|
||||
* object.
|
||||
* 3. If the function calling the handler has a return type declared
|
||||
* as errno_t, the return value of the function is passed.
|
||||
* Otherwise, a positive value of type errno_t is passed.
|
||||
* The implementation has a default constraint handler that is used if no
|
||||
* calls to the set_constraint_handler_s function have been made. The
|
||||
* behavior of the default handler is implementation-defined, and it may
|
||||
* cause the program to exit or abort. If the handler argument to
|
||||
* set_constraint_handler_s is a null pointer, the implementation default
|
||||
* handler becomes the current constraint handler.
|
||||
*
|
||||
* SPECIFIED IN
|
||||
* ISO/IEC JTC1 SC22 WG14 N1172, Programming languages, environments
|
||||
* and system software interfaces, Extensions to the C Library,
|
||||
* Part I: Bounds-checking interfaces
|
||||
*
|
||||
* INPUT PARAMETERS
|
||||
* *msg Pointer to the message describing the error
|
||||
*
|
||||
* *ptr Pointer to aassociated data. Can be NULL.
|
||||
*
|
||||
* error The error code encountered.
|
||||
*
|
||||
* OUTPUT PARAMETERS
|
||||
* none
|
||||
*
|
||||
* RETURN VALUE
|
||||
* none
|
||||
*
|
||||
* ALSO SEE
|
||||
* set_str_constraint_handler_s()
|
||||
*/
|
||||
constraint_handler_t
|
||||
set_str_constraint_handler_s (constraint_handler_t handler)
|
||||
{
|
||||
constraint_handler_t prev_handler = str_handler;
|
||||
if (NULL == handler) {
|
||||
str_handler = sl_default_handler;
|
||||
} else {
|
||||
str_handler = handler;
|
||||
}
|
||||
return prev_handler;
|
||||
}
|
||||
EXPORT_SYMBOL(set_str_constraint_handler_s);
|
||||
|
||||
|
||||
/**
|
||||
* NAME
|
||||
* invoke_safe_str_constraint_handler
|
||||
*
|
||||
* SYNOPSIS
|
||||
* #include "safe_str_constraint.h"
|
||||
* void
|
||||
* invoke_safe_str_constraint_handler (const char *msg,
|
||||
* void *ptr,
|
||||
* errno_t error)
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Invokes the currently set constraint handler or the default.
|
||||
*
|
||||
* INPUT PARAMETERS
|
||||
* *msg Pointer to the message describing the error
|
||||
*
|
||||
* *ptr Pointer to aassociated data. Can be NULL.
|
||||
*
|
||||
* error The error code encountered.
|
||||
*
|
||||
* OUTPUT PARAMETERS
|
||||
* none
|
||||
*
|
||||
* RETURN VALUE
|
||||
* none
|
||||
*
|
||||
*/
|
||||
void
|
||||
invoke_safe_str_constraint_handler (const char *msg,
|
||||
void *ptr,
|
||||
errno_t error)
|
||||
{
|
||||
if (NULL != str_handler) {
|
||||
str_handler(msg, ptr, error);
|
||||
} else {
|
||||
sl_default_handler(msg, ptr, error);
|
||||
}
|
||||
}
|
64
casadm/safeclib/safe_str_constraint.h
Normal file
64
casadm/safeclib/safe_str_constraint.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*------------------------------------------------------------------
|
||||
* safe_str_constraint.h
|
||||
*
|
||||
* October 2008, Bo Berry
|
||||
*
|
||||
* Copyright (c) 2008-2011 Cisco Systems
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef __SAFE_STR_CONSTRAINT_H__
|
||||
#define __SAFE_STR_CONSTRAINT_H__
|
||||
|
||||
#include "safeclib_private.h"
|
||||
|
||||
/*
|
||||
* Function used by the libraries to invoke the registered
|
||||
* runtime-constraint handler. Always needed.
|
||||
*/
|
||||
extern void invoke_safe_str_constraint_handler(
|
||||
const char *msg,
|
||||
void *ptr,
|
||||
errno_t error);
|
||||
|
||||
|
||||
/*
|
||||
* Safe C Lib internal string routine to consolidate error handling
|
||||
*/
|
||||
static inline void handle_error(char *orig_dest, rsize_t orig_dmax,
|
||||
char *err_msg, errno_t err_code)
|
||||
{
|
||||
#ifdef SAFECLIB_STR_NULL_SLACK
|
||||
/* null string to eliminate partial copy */
|
||||
while (orig_dmax) { *orig_dest = '\0'; orig_dmax--; orig_dest++; }
|
||||
#else
|
||||
*orig_dest = '\0';
|
||||
#endif
|
||||
|
||||
invoke_safe_str_constraint_handler(err_msg, NULL, err_code);
|
||||
return;
|
||||
}
|
||||
|
||||
#endif /* __SAFE_STR_CONSTRAINT_H__ */
|
71
casadm/safeclib/safe_str_lib.h
Normal file
71
casadm/safeclib/safe_str_lib.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/*------------------------------------------------------------------
|
||||
* safe_str_lib.h -- Safe C Library String APIs
|
||||
*
|
||||
* October 2008, Bo Berry
|
||||
*
|
||||
* Copyright (c) 2008-2011, 2013 by Cisco Systems, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef __SAFE_STR_LIB_H__
|
||||
#define __SAFE_STR_LIB_H__
|
||||
|
||||
#include "safe_lib.h"
|
||||
|
||||
/*
|
||||
* The shortest string is a null string!!
|
||||
*/
|
||||
#define RSIZE_MIN_STR ( 1 )
|
||||
|
||||
/* maximum sring length */
|
||||
#define RSIZE_MAX_STR ( 4UL << 10 ) /* 4KB */
|
||||
|
||||
|
||||
/* The makeup of a password */
|
||||
#define SAFE_STR_MIN_LOWERCASE ( 2 )
|
||||
#define SAFE_STR_MIN_UPPERCASE ( 2 )
|
||||
#define SAFE_STR_MIN_NUMBERS ( 1 )
|
||||
#define SAFE_STR_MIN_SPECIALS ( 1 )
|
||||
|
||||
#define SAFE_STR_PASSWORD_MIN_LENGTH ( 6 )
|
||||
#define SAFE_STR_PASSWORD_MAX_LENGTH ( 32 )
|
||||
|
||||
/* set string constraint handler */
|
||||
extern constraint_handler_t
|
||||
set_str_constraint_handler_s(constraint_handler_t handler);
|
||||
|
||||
/* fitted string copy */
|
||||
extern errno_t
|
||||
strncpy_s(char *dest, rsize_t dmax, const char *src, rsize_t slen);
|
||||
|
||||
/* string length */
|
||||
extern rsize_t
|
||||
strnlen_s (const char *s, rsize_t smax);
|
||||
|
||||
/* string tokenizer */
|
||||
extern char *
|
||||
strtok_s(char *s1, rsize_t *s1max, const char *src, char **ptr);
|
||||
|
||||
#endif /* __SAFE_STR_LIB_H__ */
|
59
casadm/safeclib/safe_types.h
Normal file
59
casadm/safeclib/safe_types.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*------------------------------------------------------------------
|
||||
* safe_types.h - C99 std types & defs or Linux kernel equivalents
|
||||
*
|
||||
* March 2007, Bo Berry
|
||||
* Modified 2012, Jonathan Toppins <jtoppins@users.sourceforge.net>
|
||||
*
|
||||
* Copyright (c) 2007-2013 by Cisco Systems, Inc
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef __SAFE_TYPES_H__
|
||||
#define __SAFE_TYPES_H__
|
||||
|
||||
#ifdef __KERNEL__
|
||||
/* linux kernel environment */
|
||||
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
|
||||
/* errno_t isn't defined in the kernel */
|
||||
typedef int errno_t;
|
||||
|
||||
#else
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
|
||||
typedef int errno_t;
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* __SAFE_TYPES_H__ */
|
93
casadm/safeclib/safeclib_private.h
Normal file
93
casadm/safeclib/safeclib_private.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/*------------------------------------------------------------------
|
||||
* safeclib_private.h - Internal library references
|
||||
*
|
||||
* 2012, Jonathan Toppins <jtoppins@users.sourceforge.net>
|
||||
*
|
||||
* Copyright (c) 2012, 2013 by Cisco Systems, Inc
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef __SAFECLIB_PRIVATE_H__
|
||||
#define __SAFECLIB_PRIVATE_H__
|
||||
|
||||
#ifdef __KERNEL__
|
||||
/* linux kernel environment */
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/ctype.h>
|
||||
|
||||
#define RCNEGATE(x) ( -(x) )
|
||||
|
||||
#define slprintf(...) printk(KERN_EMERG __VA_ARGS__)
|
||||
#define slabort()
|
||||
#ifdef DEBUG
|
||||
#define sldebug_printf(...) printk(KERN_DEBUG __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#else /* !__KERNEL__ */
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#ifdef STDC_HEADERS
|
||||
# include <ctype.h>
|
||||
# include <stdlib.h>
|
||||
# include <stddef.h>
|
||||
#else
|
||||
# ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
#endif
|
||||
#ifdef HAVE_STRING_H
|
||||
# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
|
||||
# include <memory.h>
|
||||
# endif
|
||||
# include <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_LIMITS_H
|
||||
# include <limits.h>
|
||||
#endif
|
||||
|
||||
#define EXPORT_SYMBOL(sym)
|
||||
#define RCNEGATE(x) (x)
|
||||
|
||||
#define slprintf(...) fprintf(stderr, __VA_ARGS__)
|
||||
#define slabort() abort()
|
||||
#ifdef DEBUG
|
||||
#define sldebug_printf(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#ifndef sldebug_printf
|
||||
#define sldebug_printf(...)
|
||||
#endif
|
||||
|
||||
#include "safe_lib.h"
|
||||
|
||||
#endif /* __SAFECLIB_PRIVATE_H__ */
|
238
casadm/safeclib/strncpy_s.c
Normal file
238
casadm/safeclib/strncpy_s.c
Normal file
@@ -0,0 +1,238 @@
|
||||
/*------------------------------------------------------------------
|
||||
* strncpy_s.c
|
||||
*
|
||||
* October 2008, Bo Berry
|
||||
*
|
||||
* Copyright (c) 2008-2011 by Cisco Systems, Inc
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "safeclib_private.h"
|
||||
#include "safe_str_constraint.h"
|
||||
#include "safe_str_lib.h"
|
||||
|
||||
|
||||
/*
|
||||
* NAME
|
||||
* strncpy_s
|
||||
*
|
||||
* SYNOPSIS
|
||||
* #include "safe_str_lib.h"
|
||||
* errno_t
|
||||
* strncpy_s(char *dest, rsize_t dmax, const char *src, rsize_t slen)
|
||||
*
|
||||
* DESCRIPTION
|
||||
* The strncpy_s function copies not more than slen successive characters
|
||||
* (characters that follow a null character are not copied) from the
|
||||
* array pointed to by src to the array pointed to by dest. If no null
|
||||
* character was copied from src, then dest[n] is set to a null character.
|
||||
*
|
||||
* All elements following the terminating null character (if any)
|
||||
* written by strncpy_s in the array of dmax characters pointed to
|
||||
* by dest take on the null value when strncpy_s returns.
|
||||
*
|
||||
* Specicified in:
|
||||
* ISO/IEC TR 24731-1, Programming languages, environments
|
||||
* and system software interfaces, Extensions to the C Library,
|
||||
* Part I: Bounds-checking interfaces
|
||||
*
|
||||
* INPUT PARAMETERS
|
||||
* dest pointer to string that will be replaced by src.
|
||||
* The resulting string is null terminated.
|
||||
*
|
||||
* dmax restricted maximum length of the resulting dest,
|
||||
* including the null
|
||||
*
|
||||
* src pointer to the string that will be copied
|
||||
* to string dest
|
||||
*
|
||||
* slen the maximum number of characters to copy from src
|
||||
*
|
||||
* OUTPUT PARAMETERS
|
||||
* dest updated with src string
|
||||
*
|
||||
* RUNTIME CONSTRAINTS
|
||||
* Neither dmax nor slen shall be equal to zero.
|
||||
* Neither dmax nor slen shall be equal zero.
|
||||
* Neither dmax nor slen shall be greater than RSIZE_MAX_STR.
|
||||
* If slen is either greater than or equal to dmax, then dmax
|
||||
* should be more than strnlen_s(src,dmax)
|
||||
* Copying shall not take place between objects that overlap.
|
||||
* If there is a runtime-constraint violation, then if dest
|
||||
* is not a null pointer and dmax greater than RSIZE_MAX_STR,
|
||||
* then strncpy_s nulls dest.
|
||||
*
|
||||
* RETURN VALUE
|
||||
* EOK successful operation, the characters in src were copied
|
||||
* to dest and the result is null terminated.
|
||||
* ESNULLP NULL pointer
|
||||
* ESZEROL zero length
|
||||
* ESLEMAX length exceeds max limit
|
||||
* ESOVRLP strings overlap
|
||||
* ESNOSPC not enough space to copy src
|
||||
*
|
||||
* ALSO SEE
|
||||
* strcat_s(), strncat_s(), strcpy_s()
|
||||
*-
|
||||
*/
|
||||
errno_t
|
||||
strncpy_s (char *dest, rsize_t dmax, const char *src, rsize_t slen)
|
||||
{
|
||||
rsize_t orig_dmax;
|
||||
char *orig_dest;
|
||||
const char *overlap_bumper;
|
||||
|
||||
if (dest == NULL) {
|
||||
invoke_safe_str_constraint_handler("strncpy_s: dest is null",
|
||||
NULL, ESNULLP);
|
||||
return RCNEGATE(ESNULLP);
|
||||
}
|
||||
|
||||
if (dmax == 0) {
|
||||
invoke_safe_str_constraint_handler("strncpy_s: dmax is 0",
|
||||
NULL, ESZEROL);
|
||||
return RCNEGATE(ESZEROL);
|
||||
}
|
||||
|
||||
if (dmax > RSIZE_MAX_STR) {
|
||||
invoke_safe_str_constraint_handler("strncpy_s: dmax exceeds max",
|
||||
NULL, ESLEMAX);
|
||||
return RCNEGATE(ESLEMAX);
|
||||
}
|
||||
|
||||
/* hold base in case src was not copied */
|
||||
orig_dmax = dmax;
|
||||
orig_dest = dest;
|
||||
|
||||
if (src == NULL) {
|
||||
handle_error(orig_dest, orig_dmax, "strncpy_s: "
|
||||
"src is null",
|
||||
ESNULLP);
|
||||
return RCNEGATE(ESNULLP);
|
||||
}
|
||||
|
||||
if (slen == 0) {
|
||||
handle_error(orig_dest, orig_dmax, "strncpy_s: "
|
||||
"slen is zero",
|
||||
ESZEROL);
|
||||
return RCNEGATE(ESZEROL);
|
||||
}
|
||||
|
||||
if (slen > RSIZE_MAX_STR) {
|
||||
handle_error(orig_dest, orig_dmax, "strncpy_s: "
|
||||
"slen exceeds max",
|
||||
ESLEMAX);
|
||||
return RCNEGATE(ESLEMAX);
|
||||
}
|
||||
|
||||
|
||||
if (dest < src) {
|
||||
overlap_bumper = src;
|
||||
|
||||
while (dmax > 0) {
|
||||
if (dest == overlap_bumper) {
|
||||
handle_error(orig_dest, orig_dmax, "strncpy_s: "
|
||||
"overlapping objects",
|
||||
ESOVRLP);
|
||||
return RCNEGATE(ESOVRLP);
|
||||
}
|
||||
|
||||
if (slen == 0) {
|
||||
/*
|
||||
* Copying truncated to slen chars. Note that the TR says to
|
||||
* copy slen chars plus the null char. We null the slack.
|
||||
*/
|
||||
#ifdef SAFECLIB_STR_NULL_SLACK
|
||||
while (dmax) { *dest = '\0'; dmax--; dest++; }
|
||||
#else
|
||||
*dest = '\0';
|
||||
#endif
|
||||
return RCNEGATE(EOK);
|
||||
}
|
||||
|
||||
*dest = *src;
|
||||
if (*dest == '\0') {
|
||||
#ifdef SAFECLIB_STR_NULL_SLACK
|
||||
/* null slack */
|
||||
while (dmax) { *dest = '\0'; dmax--; dest++; }
|
||||
#endif
|
||||
return RCNEGATE(EOK);
|
||||
}
|
||||
|
||||
dmax--;
|
||||
slen--;
|
||||
dest++;
|
||||
src++;
|
||||
}
|
||||
|
||||
} else {
|
||||
overlap_bumper = dest;
|
||||
|
||||
while (dmax > 0) {
|
||||
if (src == overlap_bumper) {
|
||||
handle_error(orig_dest, orig_dmax, "strncpy_s: "
|
||||
"overlapping objects",
|
||||
ESOVRLP);
|
||||
return RCNEGATE(ESOVRLP);
|
||||
}
|
||||
|
||||
if (slen == 0) {
|
||||
/*
|
||||
* Copying truncated to slen chars. Note that the TR says to
|
||||
* copy slen chars plus the null char. We null the slack.
|
||||
*/
|
||||
#ifdef SAFECLIB_STR_NULL_SLACK
|
||||
while (dmax) { *dest = '\0'; dmax--; dest++; }
|
||||
#else
|
||||
*dest = '\0';
|
||||
#endif
|
||||
return RCNEGATE(EOK);
|
||||
}
|
||||
|
||||
*dest = *src;
|
||||
if (*dest == '\0') {
|
||||
#ifdef SAFECLIB_STR_NULL_SLACK
|
||||
/* null slack */
|
||||
while (dmax) { *dest = '\0'; dmax--; dest++; }
|
||||
#endif
|
||||
return RCNEGATE(EOK);
|
||||
}
|
||||
|
||||
dmax--;
|
||||
slen--;
|
||||
dest++;
|
||||
src++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* the entire src was not copied, so zero the string
|
||||
*/
|
||||
handle_error(orig_dest, orig_dmax, "strncpy_s: not enough "
|
||||
"space for src",
|
||||
ESNOSPC);
|
||||
return RCNEGATE(ESNOSPC);
|
||||
}
|
||||
EXPORT_SYMBOL(strncpy_s);
|
117
casadm/safeclib/strnlen_s.c
Normal file
117
casadm/safeclib/strnlen_s.c
Normal file
@@ -0,0 +1,117 @@
|
||||
/*------------------------------------------------------------------
|
||||
* strnlen_s.c
|
||||
*
|
||||
* October 2008, Bo Berry
|
||||
*
|
||||
* Copyright (c) 2008-2011 by Cisco Systems, Inc
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "safeclib_private.h"
|
||||
#include "safe_str_constraint.h"
|
||||
#include "safe_str_lib.h"
|
||||
|
||||
|
||||
/**
|
||||
* NAME
|
||||
* strnlen_s
|
||||
*
|
||||
* SYNOPSIS
|
||||
* #include "safe_str_lib.h"
|
||||
* rsize_t
|
||||
* strnlen_s(const char *dest, rsize_t dmax)
|
||||
*
|
||||
* DESCRIPTION
|
||||
* The strnlen_s function computes the length of the string pointed
|
||||
* to by dest.
|
||||
*
|
||||
* SPECIFIED IN
|
||||
* ISO/IEC TR 24731-1, Programming languages, environments
|
||||
* and system software interfaces, Extensions to the C Library,
|
||||
* Part I: Bounds-checking interfaces
|
||||
*
|
||||
* INPUT PARAMETERS
|
||||
* dest pointer to string
|
||||
*
|
||||
* dmax restricted maximum length (including null character).
|
||||
*
|
||||
* OUTPUT PARAMETERS
|
||||
* none
|
||||
*
|
||||
* RUNTIME CONSTRAINTS
|
||||
* dest shall not be a null pointer
|
||||
* dmax shall not be greater than RSIZE_MAX_STR
|
||||
* dmax shall not equal zero
|
||||
* null character shall be in first dmax characters of dest
|
||||
*
|
||||
* RETURN VALUE
|
||||
* The function returns the string length, excluding the terminating
|
||||
* null character. If dest is NULL, then strnlen_s returns 0.
|
||||
*
|
||||
* Otherwise, the strnlen_s function returns the number of characters
|
||||
* that precede the terminating null character.
|
||||
* At most the first dmax characters of dest are accessed by strnlen_s.
|
||||
*
|
||||
* ALSO SEE
|
||||
* strnterminate_s()
|
||||
*
|
||||
*/
|
||||
rsize_t
|
||||
strnlen_s (const char *dest, rsize_t dmax)
|
||||
{
|
||||
rsize_t count;
|
||||
rsize_t orig_dmax = dmax;
|
||||
|
||||
if (dest == NULL) {
|
||||
return RCNEGATE(0);
|
||||
}
|
||||
|
||||
if (dmax == 0) {
|
||||
invoke_safe_str_constraint_handler("strnlen_s: dmax is 0",
|
||||
NULL, ESZEROL);
|
||||
return RCNEGATE(0);
|
||||
}
|
||||
|
||||
if (dmax > RSIZE_MAX_STR) {
|
||||
invoke_safe_str_constraint_handler("strnlen_s: dmax exceeds max",
|
||||
NULL, ESLEMAX);
|
||||
return RCNEGATE(0);
|
||||
}
|
||||
|
||||
count = 0;
|
||||
while (*dest && dmax) {
|
||||
count++;
|
||||
dmax--;
|
||||
dest++;
|
||||
}
|
||||
if (count == orig_dmax) {
|
||||
invoke_safe_str_constraint_handler("strnlen_s: string length exceeds dmax",
|
||||
NULL, ESLEMAX);
|
||||
return RCNEGATE(0);
|
||||
}
|
||||
|
||||
return RCNEGATE(count);
|
||||
}
|
||||
EXPORT_SYMBOL(strnlen_s);
|
323
casadm/safeclib/strtok_s.c
Normal file
323
casadm/safeclib/strtok_s.c
Normal file
@@ -0,0 +1,323 @@
|
||||
/*------------------------------------------------------------------
|
||||
* strtok_s.c
|
||||
*
|
||||
* October 2008, Bo Berry
|
||||
*
|
||||
* Copyright (c) 2008-2011 by Cisco Systems, Inc
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
* files (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following
|
||||
* conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "safeclib_private.h"
|
||||
#include "safe_str_constraint.h"
|
||||
#include "safe_str_lib.h"
|
||||
|
||||
|
||||
/**
|
||||
* NAME
|
||||
* strtok_s
|
||||
*
|
||||
* SYNOPSIS
|
||||
* #include "safe_str_lib.h"
|
||||
* char *
|
||||
* strtok_s(char *dest, rsize_t *dmax, char *src, char **ptr)
|
||||
*
|
||||
* DESCRIPTION
|
||||
* A sequence of calls to the strtok_s function breaks the string
|
||||
* pointed to by dest into a sequence of tokens, each of which is
|
||||
* delimited by a character from the string pointed to by src. The
|
||||
* fourth argument points to a caller-provided char pointer into
|
||||
* which the strtok_s function stores information necessary for
|
||||
* it to continue scanning the same string.
|
||||
*
|
||||
* The first call in a sequence has a non-null first argument and
|
||||
* dmax points to an object whose value is the number of elements
|
||||
* in the character array pointed to by the first argument. The
|
||||
* first call stores an initial value in the object pointed to by
|
||||
* ptr and updates the value pointed to by dmax to reflect the
|
||||
* number of elements that remain in relation to ptr. Subsequent
|
||||
* calls in the sequence have a null first argument and the objects
|
||||
* pointed to by dmax and ptr are required to have the values
|
||||
* stored by the previous call in the sequence, which are then
|
||||
* updated. The separator string pointed to by src may be different
|
||||
* from call to call.
|
||||
*
|
||||
* The first call in the sequence searches the string pointed to
|
||||
* by dest for the first character that is not contained in the
|
||||
* current separator string pointed to by src. If no such character
|
||||
* is found, then there are no tokens in the string pointed to
|
||||
* by dest and the strtok_s function returns a null pointer. If
|
||||
* such a character is found, it is the start of the first token.
|
||||
*
|
||||
* The strtok_s function then searches from there for the first
|
||||
* character in dest that is contained in the current separator
|
||||
* string. If no such character is found, the current token
|
||||
* extends to the end of the string pointed to by dest, and
|
||||
* subsequent searches in the same string for a token return
|
||||
* a null pointer. If such a character is found, it is
|
||||
* overwritten by a null character, which terminates the
|
||||
* current token.
|
||||
*
|
||||
* In all cases, the strtok_s function stores sufficient information
|
||||
* in the pointer pointed to by ptr so that subsequent calls,
|
||||
* with a null pointer for dest and the unmodified pointer value
|
||||
* for ptr, shall start searching just past the element overwritten
|
||||
* by a null character (if any).
|
||||
*
|
||||
* SPECIFIED IN
|
||||
* ISO/IEC TR 24731-1, Programming languages, environments
|
||||
* and system software interfaces, Extensions to the C Library,
|
||||
* Part I: Bounds-checking interfaces
|
||||
*
|
||||
* INPUT PARAMETERS
|
||||
* dest pointer to string to tokenize
|
||||
*
|
||||
* dmax restricted maximum length of dest string
|
||||
*
|
||||
* src pointer to delimiter string (len < 255)
|
||||
*
|
||||
* ptr returned pointer to token
|
||||
*
|
||||
* OUTPUT PARAMETERS
|
||||
* dmax update length
|
||||
*
|
||||
* ptr update pointer to token
|
||||
*
|
||||
* RUNTIME CONSTRAINTS
|
||||
* src shall not be a null pointer.
|
||||
* ptr shall not be a null pointer.
|
||||
* dmax shall not be a null pointer.
|
||||
* *dmax shall not be 0.
|
||||
*
|
||||
* If dest is a null pointer, then *ptr shall not be a null pointer.
|
||||
*
|
||||
* dest must not be unterminated.
|
||||
*
|
||||
* The value of *dmax shall not be greater than RSIZE_MAX_STR. The
|
||||
* end of the token found shall occur within the first *dmax
|
||||
* characters of dest for the first call, and shall occur within
|
||||
* the first *dmax characters of where searching resumes on
|
||||
* subsequent calls.
|
||||
*
|
||||
* RETURN VALUE
|
||||
* The strtok_s function returns a pointer to the first character
|
||||
* of a token; or a null pointer if there is no token or there
|
||||
* is a runtime-constraint violation.
|
||||
*
|
||||
* EOK
|
||||
* ESNULLP NULL pointer
|
||||
* ESZEROL zero length
|
||||
* ESLEMAX length exceeds max limit
|
||||
* ESUNTERM unterminated string
|
||||
*
|
||||
* EXAMPLES
|
||||
* [1] Sequencial strtok_s() calls to tokenize a string
|
||||
*
|
||||
* String to tokenize str1 = ",.:*one,two;three,;four*.*.five-six***"
|
||||
* len=38
|
||||
* String of delimiters str2 = ",.;*"
|
||||
*
|
||||
* p2tok = strtok_s(str1, &len, str2, &p2str);
|
||||
* token -one- remaining -two;three,;four*.*.five-six***- len=30
|
||||
*
|
||||
* p2tok = strtok_s(NULL, &len, str2, &p2str);
|
||||
* token -two- remaining -three,;four*.*.five-six***- len=26
|
||||
*
|
||||
* p2tok = strtok_s(NULL, &len, str2, &p2str);
|
||||
* token -three- remaining -;four*.*.five-six***- len=20
|
||||
*
|
||||
* p2tok = strtok_s(NULL, &len, str2, &p2str);
|
||||
* token -four- remaining -.*.five-six***- len=14
|
||||
*
|
||||
* p2tok = strtok_s(NULL, &len, str2, &p2str);
|
||||
* token -five-six- remaining -**- len=2
|
||||
*
|
||||
* p2tok = strtok_s(NULL, &len, str2, &p2str);
|
||||
* token -(null)- remaining -**- len=0
|
||||
*
|
||||
*
|
||||
* [2] While loop with same entry data as [1]
|
||||
*
|
||||
* p2tok = str1;
|
||||
* while (p2tok && len) {
|
||||
* p2tok = strtok_s(NULL, &len, str2, &p2str);
|
||||
* printf(" token -- remaining -- len=0 \n",
|
||||
* p2tok, p2str, (int)len );
|
||||
* }
|
||||
*
|
||||
*-
|
||||
*/
|
||||
char *
|
||||
strtok_s(char *dest, rsize_t *dmax, const char *src, char **ptr)
|
||||
{
|
||||
|
||||
/*
|
||||
* CONFIGURE: The spec does not call out a maximum for the src
|
||||
* string, so one is defined here.
|
||||
*/
|
||||
#define STRTOK_DELIM_MAX_LEN ( 16 )
|
||||
|
||||
|
||||
const char *pt;
|
||||
char *ptoken;
|
||||
rsize_t dlen;
|
||||
rsize_t slen;
|
||||
|
||||
if (dmax == NULL) {
|
||||
invoke_safe_str_constraint_handler("strtok_s: dmax is NULL",
|
||||
NULL, ESNULLP);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (*dmax == 0) {
|
||||
invoke_safe_str_constraint_handler("strtok_s: dmax is 0",
|
||||
NULL, ESZEROL);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (*dmax > RSIZE_MAX_STR) {
|
||||
invoke_safe_str_constraint_handler("strtok_s: dmax exceeds max",
|
||||
NULL, ESLEMAX);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (src == NULL) {
|
||||
invoke_safe_str_constraint_handler("strtok_s: src is null",
|
||||
NULL, ESNULLP);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (ptr == NULL) {
|
||||
invoke_safe_str_constraint_handler("strtok_s: ptr is null",
|
||||
NULL, ESNULLP);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* if the source was NULL, use the tokenizer context */
|
||||
if (dest == NULL) {
|
||||
dest = *ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* scan dest for a delimiter
|
||||
*/
|
||||
dlen = *dmax;
|
||||
ptoken = NULL;
|
||||
while (*dest != '\0' && !ptoken) {
|
||||
|
||||
if (dlen == 0) {
|
||||
*ptr = NULL;
|
||||
invoke_safe_str_constraint_handler(
|
||||
"strtok_s: dest is unterminated",
|
||||
NULL, ESUNTERM);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* must scan the entire delimiter list
|
||||
* ISO should have included a delimiter string limit!!
|
||||
*/
|
||||
slen = STRTOK_DELIM_MAX_LEN;
|
||||
pt = src;
|
||||
while (*pt != '\0') {
|
||||
|
||||
if (slen == 0) {
|
||||
*ptr = NULL;
|
||||
invoke_safe_str_constraint_handler(
|
||||
"strtok_s: src is unterminated",
|
||||
NULL, ESUNTERM);
|
||||
return (NULL);
|
||||
}
|
||||
slen--;
|
||||
|
||||
if (*dest == *pt) {
|
||||
ptoken = NULL;
|
||||
break;
|
||||
} else {
|
||||
pt++;
|
||||
ptoken = dest;
|
||||
}
|
||||
}
|
||||
dest++;
|
||||
dlen--;
|
||||
}
|
||||
|
||||
/*
|
||||
* if the beginning of a token was not found, then no
|
||||
* need to continue the scan.
|
||||
*/
|
||||
if (ptoken == NULL) {
|
||||
*dmax = dlen;
|
||||
return (ptoken);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we need to locate the end of the token
|
||||
*/
|
||||
while (*dest != '\0') {
|
||||
|
||||
if (dlen == 0) {
|
||||
*ptr = NULL;
|
||||
invoke_safe_str_constraint_handler(
|
||||
"strtok_s: dest is unterminated",
|
||||
NULL, ESUNTERM);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
slen = STRTOK_DELIM_MAX_LEN;
|
||||
pt = src;
|
||||
while (*pt != '\0') {
|
||||
|
||||
if (slen == 0) {
|
||||
*ptr = NULL;
|
||||
invoke_safe_str_constraint_handler(
|
||||
"strtok_s: src is unterminated",
|
||||
NULL, ESUNTERM);
|
||||
return (NULL);
|
||||
}
|
||||
slen--;
|
||||
|
||||
if (*dest == *pt) {
|
||||
/*
|
||||
* found a delimiter, set to null
|
||||
* and return context ptr to next char
|
||||
*/
|
||||
*dest = '\0';
|
||||
*ptr = (dest + 1); /* return pointer for next scan */
|
||||
*dmax = dlen - 1; /* account for the nulled delimiter */
|
||||
return (ptoken);
|
||||
} else {
|
||||
/*
|
||||
* simply scanning through the delimiter string
|
||||
*/
|
||||
pt++;
|
||||
}
|
||||
}
|
||||
dest++;
|
||||
dlen--;
|
||||
}
|
||||
|
||||
*dmax = dlen;
|
||||
return (ptoken);
|
||||
}
|
1308
casadm/statistics_model.c
Normal file
1308
casadm/statistics_model.c
Normal file
File diff suppressed because it is too large
Load Diff
117
casadm/statistics_view.c
Normal file
117
casadm/statistics_view.c
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2019 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "cas_lib.h"
|
||||
#include "csvparse.h"
|
||||
#include "string.h"
|
||||
#include "statistics_view.h"
|
||||
#include "statistics_view_structs.h"
|
||||
#include "statistics_view_text.h"
|
||||
#include "statistics_view_csv.h"
|
||||
#include "statistics_view_raw_csv.h"
|
||||
|
||||
static struct view_t *construct_view(int format, FILE *outfile)
|
||||
{
|
||||
struct view_t *out = calloc(1, sizeof(*out));
|
||||
if (!out) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (format) {
|
||||
case CSV:
|
||||
out->process_row = csv_process_row;
|
||||
out->end_input = csv_end_input;
|
||||
out->construct = csv_construct;
|
||||
out->destruct = csv_destruct;
|
||||
break;
|
||||
case RAW_CSV:
|
||||
out->process_row = raw_csv_process_row;
|
||||
out->end_input = raw_csv_end_input;
|
||||
out->construct = raw_csv_construct;
|
||||
out->destruct = raw_csv_destruct;
|
||||
break;
|
||||
case TEXT:
|
||||
out->process_row = text_process_row;
|
||||
out->end_input = text_end_input;
|
||||
out->construct = text_construct;
|
||||
out->destruct = text_destruct;
|
||||
break;
|
||||
}
|
||||
out->outfile = outfile;
|
||||
out->construct(out);
|
||||
return out;
|
||||
};
|
||||
|
||||
void destruct_view(struct view_t* v)
|
||||
{
|
||||
v->destruct(v);
|
||||
free(v);
|
||||
}
|
||||
|
||||
#define RECOGNIZE_TYPE(t) if (!strcmp(cols[0], TAG_NAME(t))) {type = t;}
|
||||
|
||||
int stat_print_intermediate(FILE *infile, FILE *outfile)
|
||||
{
|
||||
char buf[MAX_STR_LEN] = { 0 };
|
||||
while (fgets(buf, MAX_STR_LEN, infile)) {
|
||||
fprintf(outfile, "%s", buf);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
int stat_format_output(FILE *infile, FILE *outfile, int format)
|
||||
{
|
||||
int result = 0;
|
||||
if (format == PLAIN) {
|
||||
return stat_print_intermediate(infile, outfile);
|
||||
}
|
||||
struct view_t *view = construct_view(format, outfile);
|
||||
if (!view) {
|
||||
cas_printf(LOG_ERR, "Failed to allocate memory for output generator\n");
|
||||
return 1;
|
||||
}
|
||||
CSVFILE *cf = csv_fopen(infile);
|
||||
if (!cf) {
|
||||
cas_printf(LOG_ERR, "Failed to allocate memory for CSV parser\n");
|
||||
destruct_view(view);
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (!csv_read(cf)) {
|
||||
int num_cols = csv_count_cols(cf);
|
||||
char **cols = csv_get_col_ptr(cf);
|
||||
int type = UNDEFINED_TAG;
|
||||
if (num_cols<1) {
|
||||
continue;
|
||||
}
|
||||
RECOGNIZE_TYPE(FREEFORM);
|
||||
RECOGNIZE_TYPE(KV_PAIR);
|
||||
RECOGNIZE_TYPE(TABLE_ROW);
|
||||
RECOGNIZE_TYPE(TABLE_HEADER);
|
||||
RECOGNIZE_TYPE(TABLE_SECTION);
|
||||
RECOGNIZE_TYPE(TREE_HEADER);
|
||||
RECOGNIZE_TYPE(TREE_BRANCH);
|
||||
RECOGNIZE_TYPE(TREE_LEAF);
|
||||
RECOGNIZE_TYPE(RECORD);
|
||||
RECOGNIZE_TYPE(DATA_SET);
|
||||
if (type == UNDEFINED_TAG) {
|
||||
cas_printf(LOG_ERR, "Unrecognized tag: %s\n", cols[0]);
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
if (view->process_row(view, type, num_cols-1, cols+1)) {
|
||||
cas_printf(LOG_ERR, "Failed to process row starting with: %s\n", cols[0]);
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
view->end_input(view);
|
||||
|
||||
csv_close_nu(cf);
|
||||
destruct_view(view);
|
||||
return result;
|
||||
}
|
79
casadm/statistics_view.h
Normal file
79
casadm/statistics_view.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2019 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#ifndef __STAT_VIEW
|
||||
#define __STAT_VIEW
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* each line of statistics may be assigned one fo these semantic formats,
|
||||
* to which it will be converted */
|
||||
|
||||
enum tag_type {
|
||||
FREEFORM, /**< free form text */
|
||||
KV_PAIR, /**< key value pair. sequence of kv-pairs will be aligned to
|
||||
columns, but no table-styleborders will be drawn */
|
||||
TABLE_ROW, /**< regular table row */
|
||||
TABLE_HEADER, /**< table header */
|
||||
TABLE_SECTION, /**< first row of a table section */
|
||||
DATA_SET, /**< set of records */
|
||||
RECORD, /**< one record of data */
|
||||
TREE_HEADER,
|
||||
TREE_BRANCH,
|
||||
TREE_LEAF,
|
||||
UNDEFINED_TAG /**< occurence of this (or anything else out of
|
||||
above tags) will immediately break processing */
|
||||
};
|
||||
|
||||
#define TAG(x) #x ","
|
||||
#define TAG_NAME(x) #x
|
||||
|
||||
enum format {
|
||||
TEXT, /**< output in text (formatted tables) form */
|
||||
CSV, /**< output in csv form */
|
||||
RAW_CSV, /**< csv form without transformations */
|
||||
PLAIN /**<debug setting: print intermediate format */
|
||||
};
|
||||
|
||||
/**
|
||||
* @param infile - file in statistics_view intermediate format
|
||||
* @param outfile - file to which statistics need to be printed
|
||||
* @param format - desired format of an output.
|
||||
*/
|
||||
int stat_format_output(FILE *infile, FILE *outfile, int format);
|
||||
|
||||
/*
|
||||
* EXAMPLE OF AN INTERMEDIATE FORMAT:
|
||||
*
|
||||
* DATA_SET,
|
||||
* RECORD,
|
||||
* KV_PAIR,Cache Id, 1
|
||||
* KV_PAIR,Cache Size, 5425999, [4KiB Blocks], 20.70, [GiB]
|
||||
* KV_PAIR,Cache Occupancy, 1340, [4KiB Blocks], 0.01, [GiB], 0.02, [%]
|
||||
* KV_PAIR,Metadata end offset, 79025
|
||||
* KV_PAIR,Dirty cache lines, 0
|
||||
* KV_PAIR,Clean cache lines, 1340
|
||||
* KV_PAIR,Cache Device, /dev/sdb
|
||||
* KV_PAIR,Core Devices, 15
|
||||
* KV_PAIR,Write Policy, wt
|
||||
* KV_PAIR,Eviction Policy, lru
|
||||
* KV_PAIR,Cleaning Policy, alru
|
||||
* KV_PAIR,Metadata Variant, "max (Maximum Performance, default)"
|
||||
* KV_PAIR,Metadata Memory Footprint, 345.4, [MiB]
|
||||
* KV_PAIR,Status, Running
|
||||
* TABLE_HEADER,Request statistics,Count,%
|
||||
* TABLE_SECTION,"Read hits", 180, 11.6
|
||||
* TABLE_ROW,"Read partial misses", 1, 0.1
|
||||
* TABLE_ROW,"Read full misses", 1370, 88.3
|
||||
* TABLE_ROW,"Read total", 1551, 100.0
|
||||
* TABLE_SECTION,"Write hits", 0, 0.0
|
||||
* TABLE_ROW,"Write partial misses", 0, 0.0
|
||||
* TABLE_ROW,"Write full misses", 0, 0.0
|
||||
* TABLE_ROW,"Write total", 0, 0.0
|
||||
*
|
||||
* In each of output formats, first CSV column (referred to as a "tag")
|
||||
* will be removed from output and used by formatter thread as a hint
|
||||
*/
|
||||
#endif /*__STAT_VIEW */
|
320
casadm/statistics_view_csv.c
Normal file
320
casadm/statistics_view_csv.c
Normal file
@@ -0,0 +1,320 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2019 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "statistics_view.h"
|
||||
#include "statistics_view_structs.h"
|
||||
#include "statistics_view_csv.h"
|
||||
|
||||
#define VALS_BUFFER_INIT_SIZE 10
|
||||
|
||||
/**
|
||||
* private data of CSV output formatter
|
||||
*/
|
||||
struct csv_out_prv {
|
||||
int data_set; /* current data set number */
|
||||
int record; /* current record number */
|
||||
int column; /* current column number */
|
||||
char **vals;
|
||||
char **titles;
|
||||
int max_vals;
|
||||
int cur_val;
|
||||
int max_titles;
|
||||
int cur_title;
|
||||
};
|
||||
|
||||
static inline int csv_is_first_record(struct view_t *this)
|
||||
{
|
||||
return 1 == this->ctx.csv_prv->record;
|
||||
}
|
||||
|
||||
static inline int csv_is_unit_string(const char *s)
|
||||
{
|
||||
return NULL != s && '[' == s[0];
|
||||
}
|
||||
|
||||
static void csv_output_column(struct view_t *this, const char *s)
|
||||
{
|
||||
struct csv_out_prv *prv = this->ctx.csv_prv;
|
||||
|
||||
if (prv->column) {
|
||||
putc(',', this->outfile);
|
||||
}
|
||||
|
||||
if (strstr(s, ",")) {
|
||||
fprintf(this->outfile, "\"%s\"", s);
|
||||
} else {
|
||||
fprintf(this->outfile, "%s", s);
|
||||
}
|
||||
prv->column++;
|
||||
}
|
||||
|
||||
static char **csv_check_container(char **container, int *max_vals,
|
||||
int cur_val)
|
||||
{
|
||||
if (!container) {
|
||||
*max_vals = VALS_BUFFER_INIT_SIZE;
|
||||
container = calloc(sizeof(char *), *max_vals);
|
||||
if (!container) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Resize val pointers array if needed */
|
||||
if (*max_vals < cur_val) {
|
||||
*max_vals = *max_vals * 2;
|
||||
if (*max_vals < cur_val) {
|
||||
*max_vals = cur_val;
|
||||
}
|
||||
container = realloc(container, sizeof(char *) * (*max_vals));
|
||||
if (!container) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
static int csv_output_data(struct view_t *this, const char *s)
|
||||
{
|
||||
struct csv_out_prv *prv = this->ctx.csv_prv;
|
||||
if (csv_is_first_record(this)) {
|
||||
prv->vals = csv_check_container(prv->vals, &prv->max_vals,
|
||||
prv->cur_val+1);
|
||||
if (!prv->vals) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Store value */
|
||||
prv->vals[prv->cur_val] = strdup(s);
|
||||
if (!prv->vals[prv->cur_val]) {
|
||||
return 1;
|
||||
}
|
||||
prv->cur_val++;
|
||||
} else {
|
||||
csv_output_column(this, s);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int csv_add_column_subtitle(struct view_t *this, const char *s)
|
||||
{
|
||||
struct csv_out_prv *prv = this->ctx.csv_prv;
|
||||
|
||||
prv->titles = csv_check_container(prv->titles, &prv->max_titles,
|
||||
prv->cur_title+1);
|
||||
if (!prv->titles) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Store value */
|
||||
prv->titles[prv->cur_title] = strdup(s);
|
||||
if (!prv->titles[prv->cur_title]) {
|
||||
return 1;
|
||||
}
|
||||
prv->cur_title++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void csv_output_header(struct view_t *this, const char *title,
|
||||
const char *unit)
|
||||
{
|
||||
static char buff[64];
|
||||
if (unit) {
|
||||
if (csv_is_unit_string(unit)) {
|
||||
snprintf(buff, sizeof(buff), "%s %s", title, unit);
|
||||
} else {
|
||||
snprintf(buff, sizeof(buff), "%s [%s]", title, unit);
|
||||
}
|
||||
csv_output_column(this, buff);
|
||||
} else {
|
||||
csv_output_column(this, title);
|
||||
}
|
||||
}
|
||||
|
||||
static void csv_finish_record(struct view_t *this)
|
||||
{
|
||||
struct csv_out_prv *prv = this->ctx.csv_prv;
|
||||
int i;
|
||||
|
||||
if (prv->column) {
|
||||
putc('\n', this->outfile);
|
||||
}
|
||||
|
||||
/*
|
||||
* For first record we need to output stored data values
|
||||
*/
|
||||
if (csv_is_first_record(this)) {
|
||||
prv->column = 0;
|
||||
for (i = 0; i < prv->cur_val; ++i) {
|
||||
csv_output_column(this, prv->vals[i]);
|
||||
}
|
||||
if (prv->column) {
|
||||
putc('\n', this->outfile);
|
||||
}
|
||||
}
|
||||
fflush(this->outfile);
|
||||
}
|
||||
|
||||
static void csv_free_vals(struct view_t *this)
|
||||
{
|
||||
struct csv_out_prv *prv = this->ctx.csv_prv;
|
||||
int i;
|
||||
|
||||
if (prv->vals) {
|
||||
for (i = 0; i < prv->cur_val; ++i) {
|
||||
free(prv->vals[i]);
|
||||
}
|
||||
free(prv->vals);
|
||||
prv->vals = NULL;
|
||||
prv->cur_val = 0;
|
||||
prv->max_vals = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void csv_free_titles(struct view_t *this)
|
||||
{
|
||||
struct csv_out_prv *prv = this->ctx.csv_prv;
|
||||
int i;
|
||||
|
||||
if (prv->titles) {
|
||||
for (i = 0; i < prv->cur_title; ++i) {
|
||||
free(prv->titles[i]);
|
||||
}
|
||||
free(prv->titles);
|
||||
prv->titles = NULL;
|
||||
prv->cur_title = 0;
|
||||
prv->max_titles = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int csv_process_row(struct view_t *this, int type, int num_fields, char *fields[])
|
||||
{
|
||||
int i;
|
||||
struct csv_out_prv *prv = this->ctx.csv_prv;
|
||||
const char *unit = NULL;
|
||||
|
||||
switch (type) {
|
||||
case DATA_SET:
|
||||
if (prv->record) {
|
||||
csv_finish_record(this);
|
||||
}
|
||||
csv_free_titles(this);
|
||||
csv_free_vals(this);
|
||||
if (prv->data_set) {
|
||||
putc('\n', this->outfile);
|
||||
}
|
||||
if (num_fields > 0) {
|
||||
fprintf(this->outfile, "%s\n", fields[0]);
|
||||
}
|
||||
prv->record = 0;
|
||||
prv->data_set++;
|
||||
break;
|
||||
case RECORD:
|
||||
if (prv->record) {
|
||||
csv_finish_record(this);
|
||||
}
|
||||
prv->column = 0;
|
||||
prv->record++;
|
||||
break;
|
||||
|
||||
/*
|
||||
* For KV pair assume that values are interleaved
|
||||
* with units, so output every second value,
|
||||
* and use units to construct column headers.
|
||||
* For example:
|
||||
* KV_PAIR,Cache Size,10347970,[4KiB blocks],39.47,[GiB]
|
||||
* will result in:
|
||||
* data row: 10347970,39.47
|
||||
* header row: Cache Size [4KiB blocks],Cache Size [GiB]
|
||||
*/
|
||||
case KV_PAIR:
|
||||
for (i = 1; i < num_fields; i += 2) {
|
||||
if (csv_is_first_record(this)) {
|
||||
if (i + 1 < num_fields) {
|
||||
csv_output_header(this, fields[0],
|
||||
fields[i+1]);
|
||||
} else {
|
||||
csv_output_header(this, fields[0], NULL);
|
||||
}
|
||||
}
|
||||
if (csv_output_data(this, fields[i])) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/*
|
||||
* For table rows assume the following format:
|
||||
* TABLE_{ROW,SECTION},Title,value1,value2,value3,...,unit
|
||||
* This will result in:
|
||||
* data row: value1,value2,value3,...
|
||||
* header row: Title [unit],Title [col1_title],Title [col2_title],...
|
||||
*/
|
||||
case TABLE_HEADER:
|
||||
csv_free_titles(this);
|
||||
csv_add_column_subtitle(this, "");
|
||||
for (i = 2; i < num_fields; i++) {
|
||||
if (csv_add_column_subtitle(this, fields[i])) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TABLE_SECTION:
|
||||
case TABLE_ROW:
|
||||
if (csv_is_first_record(this)) {
|
||||
unit = NULL;
|
||||
if (csv_is_unit_string(fields[num_fields-1])) {
|
||||
unit = fields[num_fields-1];
|
||||
}
|
||||
csv_output_header(this, fields[0], unit);
|
||||
for (i = 2; i < num_fields; i++) {
|
||||
if (!csv_is_unit_string(prv->titles[i-1])) {
|
||||
csv_output_header(this, fields[0],
|
||||
prv->titles[i-1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 1; i < num_fields; i++) {
|
||||
if (!csv_is_unit_string(prv->titles[i-1])) {
|
||||
if (csv_output_data(this, fields[i])) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int csv_end_input(struct view_t *this)
|
||||
{
|
||||
csv_finish_record(this);
|
||||
return 0;
|
||||
}
|
||||
int csv_construct(struct view_t *this)
|
||||
{
|
||||
struct csv_out_prv *prv = calloc(sizeof(struct csv_out_prv), 1);
|
||||
|
||||
if (!prv) {
|
||||
return 1;
|
||||
}
|
||||
this->ctx.csv_prv = prv;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int csv_destruct(struct view_t *this)
|
||||
{
|
||||
csv_free_vals(this);
|
||||
csv_free_titles(this);
|
||||
free(this->ctx.csv_prv);
|
||||
return 0;
|
||||
}
|
||||
|
18
casadm/statistics_view_csv.h
Normal file
18
casadm/statistics_view_csv.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2019 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#ifndef __STATS_VIEW_CSV
|
||||
#define __STATS_VIEW_CSV
|
||||
|
||||
int csv_process_row(struct view_t *this, int type, int num_fields, char *fields[]);
|
||||
|
||||
int csv_end_input(struct view_t *this);
|
||||
|
||||
int csv_construct(struct view_t *this);
|
||||
|
||||
int csv_destruct(struct view_t *this);
|
||||
|
||||
|
||||
#endif
|
49
casadm/statistics_view_raw_csv.c
Normal file
49
casadm/statistics_view_raw_csv.c
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2019 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "statistics_view.h"
|
||||
#include "statistics_view_structs.h"
|
||||
#include "statistics_view_raw_csv.h"
|
||||
|
||||
#define VALS_BUFFER_INIT_SIZE 10
|
||||
|
||||
int raw_csv_process_row(struct view_t *this, int type, int num_fields, char *fields[])
|
||||
{
|
||||
int i;
|
||||
if (RECORD != type && DATA_SET != type) {
|
||||
for (i = 0; i < num_fields; i++) {
|
||||
if (i) {
|
||||
fputc(',', this->outfile);
|
||||
}
|
||||
if (strstr(fields[i], ",")) {
|
||||
fprintf(this->outfile, "\"%s\"", fields[i]);
|
||||
} else {
|
||||
fprintf(this->outfile, "%s", fields[i]);
|
||||
}
|
||||
}
|
||||
fputc('\n', this->outfile);
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int raw_csv_end_input(struct view_t *this)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int raw_csv_construct(struct view_t *this)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int raw_csv_destruct(struct view_t *this)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
18
casadm/statistics_view_raw_csv.h
Normal file
18
casadm/statistics_view_raw_csv.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2019 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#ifndef __STATS_VIEW_RAW_CSV
|
||||
#define __STATS_VIEW_RAW_CSV
|
||||
|
||||
int raw_csv_process_row(struct view_t *this, int type, int num_fields, char *fields[]);
|
||||
|
||||
int raw_csv_end_input(struct view_t *this);
|
||||
|
||||
int raw_csv_construct(struct view_t *this);
|
||||
|
||||
int raw_csv_destruct(struct view_t *this);
|
||||
|
||||
|
||||
#endif
|
29
casadm/statistics_view_structs.h
Normal file
29
casadm/statistics_view_structs.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2019 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#ifndef __STATS_VIEW_S_H
|
||||
#define __STATS_VIEW_S_H
|
||||
|
||||
struct csv_out_prv;
|
||||
|
||||
struct text_out_prv;
|
||||
|
||||
struct view_t
|
||||
{
|
||||
FILE *outfile;
|
||||
union {
|
||||
struct csv_out_prv *csv_prv;
|
||||
struct text_out_prv *text_prv;
|
||||
} ctx;
|
||||
/* type specific init */
|
||||
int (*construct)(struct view_t *this);
|
||||
int (*process_row)(struct view_t *this, int type, int num_fields, char *fields[]);
|
||||
int (*end_input)(struct view_t *this);
|
||||
int (*destruct)(struct view_t *this);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
1025
casadm/statistics_view_text.c
Normal file
1025
casadm/statistics_view_text.c
Normal file
File diff suppressed because it is too large
Load Diff
18
casadm/statistics_view_text.h
Normal file
18
casadm/statistics_view_text.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2019 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#ifndef __STATS_VIEW_TEXT
|
||||
#define __STATS_VIEW_TEXT
|
||||
|
||||
int text_process_row(struct view_t *this, int type, int num_fields, char *fields[]);
|
||||
|
||||
int text_end_input(struct view_t *this);
|
||||
|
||||
int text_construct(struct view_t *this);
|
||||
|
||||
int text_destruct(struct view_t *this);
|
||||
|
||||
|
||||
#endif
|
231
casadm/table.c
Normal file
231
casadm/table.c
Normal file
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2019 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "table.h"
|
||||
#include "safeclib/safe_str_lib.h"
|
||||
#include <cas_ioctl_codes.h>
|
||||
|
||||
#define MIN_STR_SIZE 64
|
||||
|
||||
struct table_row
|
||||
{
|
||||
int width;
|
||||
int max_width;
|
||||
char **cells;
|
||||
};
|
||||
|
||||
|
||||
struct table
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
int max_height;
|
||||
struct table_row *r;
|
||||
};
|
||||
|
||||
struct table *table_alloc()
|
||||
{
|
||||
struct table *out = malloc(sizeof(*out));
|
||||
if (!out) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
out->width = 0;
|
||||
out->height = 0;
|
||||
out->max_height = 0;
|
||||
|
||||
out->r = 0;
|
||||
return out;
|
||||
}
|
||||
|
||||
void table_free(struct table *t)
|
||||
{
|
||||
int i, j;
|
||||
if (t->r) {
|
||||
for (i = 0 ; i!= t->max_height; ++i) {
|
||||
if (t->r[i].cells) {
|
||||
for (j = 0 ; j!= t->r[i].max_width; ++j) {
|
||||
if (t->r[i].cells[j]) {
|
||||
free(t->r[i].cells[j]);
|
||||
}
|
||||
}
|
||||
free(t->r[i].cells);
|
||||
}
|
||||
}
|
||||
free(t->r);
|
||||
}
|
||||
free(t);
|
||||
}
|
||||
int table_reset(struct table *t)
|
||||
{
|
||||
int i,j;
|
||||
if (t->r) {
|
||||
for (i = 0 ; i!= t->max_height; ++i) {
|
||||
if (t->r[i].cells) {
|
||||
for (j = 0 ; j!= t->r[i].max_width; ++j) {
|
||||
if (t->r[i].cells[j]) {
|
||||
(t->r[i].cells[j])[0] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
t->r[i].width = 0;
|
||||
}
|
||||
}
|
||||
t->width = 0;
|
||||
t->height = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int maxi(int x, int y)
|
||||
{
|
||||
if (x > y) {
|
||||
return x;
|
||||
} else {
|
||||
return y;
|
||||
}
|
||||
}
|
||||
|
||||
char *table_get(struct table *t,int y, int x)
|
||||
{
|
||||
static const char * empty="";
|
||||
if (y >= t->height || x >= t->width) {
|
||||
assert(0);
|
||||
abort();
|
||||
return (char*)empty;
|
||||
}
|
||||
|
||||
/* within assigned boundaries but without allocated boundaries */
|
||||
if (y >= t->max_height) {
|
||||
return (char*)empty;
|
||||
}
|
||||
|
||||
if (x >= t->r[y].max_width) {
|
||||
return (char*)empty;
|
||||
}
|
||||
|
||||
if (!t->r[y].cells) {
|
||||
return (char*)empty;
|
||||
}
|
||||
|
||||
if (!t->r[y].cells[x]) {
|
||||
return (char*)empty;
|
||||
}
|
||||
|
||||
return t->r[y].cells[x];
|
||||
}
|
||||
|
||||
int table_set(struct table *t, int y, int x, char *c)
|
||||
{
|
||||
int i;
|
||||
int len = strnlen(c, MAX_STR_LEN);
|
||||
if (len >= MAX_STR_LEN) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* step 1: ensure that space for row y is allocated */
|
||||
if (!t->r) {
|
||||
t->r = calloc(sizeof(struct table_row), y + 1);
|
||||
if (!t->r) {
|
||||
return 1;
|
||||
}
|
||||
t->max_height = y + 1;
|
||||
} else if (t->max_height <= y) {
|
||||
struct table_row *tmp;
|
||||
int new_m_h = t->max_height*2;
|
||||
if (new_m_h <= y) {
|
||||
new_m_h = y+1;
|
||||
}
|
||||
|
||||
tmp = realloc(t->r, sizeof(struct table_row)*new_m_h);
|
||||
if (!tmp) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
t->r=tmp;
|
||||
for (i = t->max_height; i!= new_m_h; ++i) {
|
||||
t->r[i].width = t->r[i].max_width = 0;
|
||||
t->r[i].cells = 0;
|
||||
}
|
||||
t->max_height = new_m_h;
|
||||
|
||||
} /* else everything is OK */
|
||||
|
||||
/* step 2: ensure that column x within row y is allocated */
|
||||
if (!t->r[y].cells) {
|
||||
t->r[y].cells = calloc(sizeof(char*), x + 1);
|
||||
t->r[y].max_width = x + 1;
|
||||
} else if (t->r[y].max_width <= x) {
|
||||
char **tmp;
|
||||
int new_m_w = t->r[y].max_width*2;
|
||||
if (new_m_w <= x) {
|
||||
new_m_w = x+1;
|
||||
}
|
||||
|
||||
tmp = realloc(t->r[y].cells, sizeof(char*)*new_m_w);
|
||||
if (!tmp) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
t->r[y].cells = tmp;
|
||||
memset(&tmp[t->r[y].max_width], 0,
|
||||
sizeof(char*)*(new_m_w-t->r[y].max_width));
|
||||
t->r[y].max_width = new_m_w;
|
||||
}
|
||||
|
||||
/* step 3: allocate space for string to be contained in cell */
|
||||
if (t->r[y].cells[x] && len+1>MIN_STR_SIZE) {
|
||||
char *tmp = realloc(t->r[y].cells[x], len+1);
|
||||
if (!tmp) {
|
||||
return 1;
|
||||
}
|
||||
t->r[y].cells[x] = tmp;
|
||||
|
||||
} else if (!t->r[y].cells[x]){
|
||||
t->r[y].cells[x] = malloc(maxi(MIN_STR_SIZE,len+1));
|
||||
if (!t->r[y].cells[x]) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* step 4: actually overwrite contents of a cell */
|
||||
strncpy_s(t->r[y].cells[x], len + 1, c, len);
|
||||
|
||||
/* step 5: update width and height of a table */
|
||||
|
||||
t->height = maxi(t->height, y + 1);
|
||||
t->width = maxi(t->width, x + 1);
|
||||
t->r[y].width = maxi(t->r[y].width, x + 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* get last available row of table that was added either via
|
||||
*/
|
||||
int table_get_width(struct table *t)
|
||||
{
|
||||
return t->width;
|
||||
}
|
||||
|
||||
int table_get_height(struct table *t)
|
||||
{
|
||||
return t->height;
|
||||
}
|
||||
|
||||
int table_set_height(struct table *t, int h)
|
||||
{
|
||||
t->height = h;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int table_set_width(struct table *t, int h)
|
||||
{
|
||||
t->width = h;
|
||||
return 0;
|
||||
}
|
||||
|
58
casadm/table.h
Normal file
58
casadm/table.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2019 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __TABLE_H
|
||||
#define __TABLE_H
|
||||
|
||||
struct table;
|
||||
|
||||
/**
|
||||
* setup "table" structure.
|
||||
*/
|
||||
struct table *table_alloc();
|
||||
|
||||
/**
|
||||
* deallocate table.
|
||||
*/
|
||||
void table_free(struct table *t);
|
||||
|
||||
/**
|
||||
* max value of two integers
|
||||
*/
|
||||
int maxi(int x, int y);
|
||||
|
||||
/**
|
||||
* retrieve a field of a table
|
||||
*/
|
||||
char *table_get(struct table *t,int y, int x);
|
||||
|
||||
int table_set(struct table *t, int y, int x, char *c);
|
||||
|
||||
/**
|
||||
* reduce number of columns and rows to 0;
|
||||
*/
|
||||
int table_reset(struct table *t);
|
||||
|
||||
/**
|
||||
* get last available column of table that was added via table_set
|
||||
*/
|
||||
int table_get_width(struct table *t);
|
||||
|
||||
/**
|
||||
* get last available row of table that was added either via table_set or table_set_height
|
||||
*/
|
||||
int table_get_height(struct table *t);
|
||||
|
||||
/**
|
||||
* set height of a table (additional rows will contain empty strings
|
||||
*/
|
||||
int table_set_height(struct table *t, int h);
|
||||
/**
|
||||
* set with of a table (additional rows will contain empty strings
|
||||
*/
|
||||
int table_set_width(struct table *t, int h);
|
||||
|
||||
#endif
|
40
casadm/upgrade.c
Normal file
40
casadm/upgrade.c
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2019 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include "cas_lib.h"
|
||||
#include "cas_lib_utils.h"
|
||||
#include <cas_ioctl_codes.h>
|
||||
|
||||
extern cas_printf_t cas_printf;
|
||||
|
||||
int upgrade_start()
|
||||
{
|
||||
int fd;
|
||||
struct kcas_upgrade cmd_info;
|
||||
|
||||
if ((fd = open_ctrl_device()) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (run_ioctl_interruptible(fd, KCAS_IOCTL_UPGRADE, &cmd_info,
|
||||
"Starting upgrade", 0, OCF_CORE_ID_INVALID) < 0) {
|
||||
close(fd);
|
||||
if (OCF_ERR_FLUSHING_INTERRUPTED == cmd_info.ext_err_code) {
|
||||
return INTERRUPTED;
|
||||
} else {
|
||||
cas_printf(LOG_ERR, "Error starting upgrade\n");
|
||||
print_err(cmd_info.ext_err_code);
|
||||
return FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return SUCCESS;
|
||||
}
|
11
casadm/upgrade.h
Normal file
11
casadm/upgrade.h
Normal file
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2019 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
#ifndef _UPGRADE_H
|
||||
#define _UPGRADE_H
|
||||
|
||||
int upgrade_start();
|
||||
|
||||
#endif
|
119
casadm/vt100codes.h
Normal file
119
casadm/vt100codes.h
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright(c) 2012-2019 Intel Corporation
|
||||
* SPDX-License-Identifier: BSD-3-Clause-Clear
|
||||
*/
|
||||
|
||||
/* General setup */
|
||||
#define RESET_DEVICE "\033c"
|
||||
//! enable line wrapping
|
||||
#define ENABLE_LINE_WRAP "\x1b[7h"
|
||||
//! disable it
|
||||
#define DISABLE_LINE_WRAP "\x1b[7l"
|
||||
|
||||
/* Scrolling options. Note: there is no way to disable scrolling */
|
||||
//! Whole screen is scrolled on SCROLL_UP/SCROLL_DOWN
|
||||
#define SCROLL_ENTIRE_SCREEN "\x1b[r"
|
||||
//! Only rows from A to B are scrolled on SCROLL_UP/SCROLL_DOWN, anything above A or below B is not scrolled
|
||||
#define SCROLL_SCREEN_REGION(A,B) "\x1b[" (A) ";" (B) "r"
|
||||
|
||||
//! scroll up
|
||||
#define SCROLL_UP "\x1b[M"
|
||||
//! scroll down
|
||||
#define SCROLL_DOWN "\x1b[D"
|
||||
|
||||
//! make cursor invisible - xterm
|
||||
#define HIDE_CURSOR "\x1b[?25l"
|
||||
|
||||
//! restore it -xterm
|
||||
#define SHOW_CURSOR "\x1b[?25h"
|
||||
|
||||
/* Absolute cursor positioning. */
|
||||
//! Set cursor position to left-top position
|
||||
#define CURSOR_HOME "\x1b[H"
|
||||
//! Set cursor position to specific y/x (note: y = 1..height, x = 1..width)
|
||||
#define CURSOR_YX "\x1b[%d;%dH"
|
||||
/* Relative cursor positioning. */
|
||||
//! move cursor one position up
|
||||
#define CURSOR_UP "\x1b[A"
|
||||
//! move cursor n positions up
|
||||
#define CURSOR_UP_N "\x1b[%dA"
|
||||
//! move cursor one position down
|
||||
#define CURSOR_DOWN "\x1b[B"
|
||||
//! move cursor n positions down
|
||||
#define CURSOR_DOWN_N "\x1b[%dB"
|
||||
//! move cursor one position forward
|
||||
#define CURSOR_FORWARD "\x1b[C"
|
||||
//! move cursor n positions forward
|
||||
#define CURSOR_FORWARD_N "\x1b[%dC"
|
||||
//! move cursor one position backward
|
||||
#define CURSOR_BACKWARD "\x1b[D"
|
||||
//! move cursor n positions backward
|
||||
#define CURSOR_BACKWARD_N "\x1b[%dD"
|
||||
/* Unsave restores position after last save. */
|
||||
//! One cursor position may be saved
|
||||
#define SAVE_CURSOR "\x1b[s"
|
||||
//! and restored
|
||||
#define UNSAVE_CURSOR "\x1b[u"
|
||||
|
||||
/* Erase screen. */
|
||||
//! Erase whole screen
|
||||
#define ERASE "\x1b[2J"
|
||||
//! same as above
|
||||
#define ERASE_SCREEN ERASE
|
||||
//! erase above cursor
|
||||
#define ERASE_UP "\x1b[1J"
|
||||
//! erase below cursor
|
||||
#define ERASE_DOWN "\x1b[J"
|
||||
|
||||
|
||||
#define INSERT_MODE "\x1b[4h"
|
||||
#define REPLACE_MODE "\x1b[4l"
|
||||
/* Erase line. */
|
||||
//! erase current line
|
||||
#define ERASE_LINE "\x1b[K"
|
||||
//! erase current line left from the cursor
|
||||
#define ERASE_START_OF_LINE "\x1b[1K"
|
||||
//! erase current line right from the cursor
|
||||
#define ERASE_END_OF_LINE "\x1b[K"
|
||||
|
||||
/* a = one of following 23 attributes*/
|
||||
//! set specific attribute
|
||||
#define SET_ATTR "\x1b[%dm"
|
||||
//! if you have to set more attributes, separate them by ";"
|
||||
#define AND_ATTR ";"
|
||||
/*generalattributes (0-8 without 3 and 6) */
|
||||
//!resets terminal defaults
|
||||
#define ATTR_RESET 0
|
||||
//!sets brighter fg color
|
||||
#define ATTR_BRIGHT 1
|
||||
//!turns off bright (sets darker fg color) note: not supported by most of platforms
|
||||
#define ATTR_DIM 2
|
||||
//!turns on text underline (not supported by MS Windows)
|
||||
#define ATTR_UNDERSCORE 4
|
||||
//!turns on blink (Not supported by MS Windows, most of other implementations incompatible)
|
||||
#define ATTR_BLINK 5
|
||||
//! Inverts bg and fg color (incompatible implementation on MS windows)*/
|
||||
#define ATTR_REVERSE 7
|
||||
|
||||
#define ATTR_HIDDEN 8 /*???*/
|
||||
|
||||
/*Foreground (text) colours*/
|
||||
#define FG_COLOR_BLACK 30
|
||||
#define FG_COLOR_RED 31
|
||||
#define FG_COLOR_GREEN 32
|
||||
#define FG_COLOR_YELLOW 33
|
||||
#define FG_COLOR_BLUE 34
|
||||
#define FG_COLOR_MAGENTA 35
|
||||
#define FG_COLOR_CYAN 36
|
||||
#define FG_COLOR_WHITE 37
|
||||
|
||||
/*Background colors*/
|
||||
#define BG_COLOR_BLACK 40
|
||||
#define BG_COLOR_RED 41
|
||||
#define BG_COLOR_GREEN 42
|
||||
#define BG_COLOR_YELLOW 43
|
||||
#define BG_COLOR_BLUE 44
|
||||
#define BG_COLOR_MAGENTA 45
|
||||
#define BG_COLOR_CYAN 46
|
||||
#define BG_COLOR_WHITE 47
|
||||
|
Reference in New Issue
Block a user