Initial commit

Signed-off-by: Robert Baldyga <robert.baldyga@intel.com>
This commit is contained in:
Robert Baldyga
2019-03-29 08:39:34 +01:00
commit 94e8ca09e0
140 changed files with 37144 additions and 0 deletions

167
casadm/Makefile Normal file
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

297
casadm/cas_lib.h Normal file
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

483
casadm/csvparse.c Normal file
View 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
View 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
View 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);
}

View 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
View 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
View 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
View 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
View 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
View 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
View 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

View 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);

View 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;
}

View 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
View 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
View 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
View 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);

View 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__ */

View 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__ */

View 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);
}
}

View 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__ */

View 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__ */

View 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);
}
}

View 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__ */

View 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__ */

View 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__ */

View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

117
casadm/statistics_view.c Normal file
View 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
View 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 */

View 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;
}

View 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

View 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;
}

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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
View 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
View 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
View 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
View 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
View 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