From 05488cad0e381dc10f54d6d9909ab7eab30f262e Mon Sep 17 00:00:00 2001 From: Ryan Harkin Date: Fri, 25 May 2012 08:36:24 +0000 Subject: Initial commit --- Makefile | 15 +++ debug_stm/my | 0 debug_stm/my_config | 0 debug_stm/request | 1 + fileop.c | 106 +++++++++++++++++ main.c | 326 ++++++++++++++++++++++++++++++++++++++++++++++++++++ test_commands.h | 72 ++++++++++++ 7 files changed, 520 insertions(+) create mode 100644 Makefile create mode 100644 debug_stm/my create mode 100644 debug_stm/my_config create mode 100644 debug_stm/request create mode 100644 fileop.c create mode 100644 main.c create mode 100644 test_commands.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1ec6fe0 --- /dev/null +++ b/Makefile @@ -0,0 +1,15 @@ + +all: stm_test + +stm_test: main.o fileop.o + gcc -o $@ $^ + +fileop.o: fileop.c + gcc -c $< + +main.o: main.c test_commands.h + gcc -c $< + +clean: + rm -rf *.o + rm stm_test diff --git a/debug_stm/my b/debug_stm/my new file mode 100644 index 0000000..e69de29 diff --git a/debug_stm/my_config b/debug_stm/my_config new file mode 100644 index 0000000..e69de29 diff --git a/debug_stm/request b/debug_stm/request new file mode 100644 index 0000000..1254345 --- /dev/null +++ b/debug_stm/request @@ -0,0 +1 @@ +user my \ No newline at end of file diff --git a/fileop.c b/fileop.c new file mode 100644 index 0000000..52e5b6d --- /dev/null +++ b/fileop.c @@ -0,0 +1,106 @@ +/* ------------------------------------------------------------------ + * fileop.c + * File related operations, such as searching file in path, list of + * files in some dir. + * ----------------------------------------------------------------*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "test_commands.h" + +#define MAX_FILEPATH_LENGTH (256) + +/* to check wether a given name is a directory or not + * Input: + * - name: the name to be checked. +Return: + * - 1: if is a directory + * - 0: if not a directory, or file doesn't exist, error + */ +static int is_dir(const char* name) +{ + struct stat buf; + + if (lstat(name, &buf) < 0) + return 0; /* if not exist, error */ + + /*if is directory return 1 ,else return 0*/ + return S_ISDIR(buf.st_mode); +} + + +/* search target file with in directory + * Input: + * - path: the path to be searched in + * - name: file name to be searched + * Return: + * - -1: error + * - 1: found + * - 0: not found + */ +int search_file(const char* path, const char* name) +{ + int ret = -1; + DIR* directory; + struct dirent* dir_entry; + char current_filename[MAX_FILEPATH_LENGTH]; + + TDBG("Enter %s. name=%s; path=%s\n", __FUNCTION__, name, path); + if ((directory = opendir(path)) == NULL) { + printf("Error opendir(%s)\n", path); + return -1; + } + + while (dir_entry = readdir(directory)) { + TDBG("dir_entry->d_name is \"%s\"\n", dir_entry->d_name); + /* To check wether this is a directory */ + if (!strcmp(dir_entry->d_name, ".") || + !strcmp(dir_entry->d_name, "..")) { + /* skip */ + continue; + } + else { + /* if is root directory */ + if ((strcmp(path, "/")) == 0) + ret = snprintf(current_filename, MAX_FILEPATH_LENGTH, "%s%s", path, dir_entry->d_name); + /* if is not root directory */ + else + ret = snprintf(current_filename, MAX_FILEPATH_LENGTH, "%s%s", path, dir_entry->d_name); + /* check if truncated */ + if (ret >= MAX_FILEPATH_LENGTH) { + printf("Critical error: exceed MAX_FILEPATH_LENGTH.\n"); + closedir(directory); + return -1; + } + } + + TDBG("Now tracking file (full path): %s\n", current_filename); + + /* if is a directory, recursively call search_file */ + if (is_dir(current_filename)) { + ret = search_file(current_filename, name); + if (ret == 1) { + TDBG("File: %s is found in directory %s\n", name, current_filename); + closedir(directory); + return ret; + } + } + else { + if (strcmp(dir_entry->d_name, name) == 0) { + TDBG("File: %s is found in directory %s.\n", name, current_filename); + closedir(directory); + return 1; + } + } + } + closedir(directory); + + /* no findings */ + return 0; +} diff --git a/main.c b/main.c new file mode 100644 index 0000000..da59887 --- /dev/null +++ b/main.c @@ -0,0 +1,326 @@ +/* Test application of STM Framework and driver + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_commands.h" + +/* global const */ +#define LOCAL_TEST_STUB +#ifdef LOCAL_TEST_STUB +const char* DEBUGFS_STM = "./debug_stm/"; +#else +const char* DEBUGFS_STM = "/sys/kernel/debug/stm/"; +#endif + +pthread_mutex_t mux; + +command_list stm_test_command_list[] = { + { + "create_chan", + stm_create_channel, + true, + false, + stm_create_channel_sync_verify, + NULL, + }, + { + "info", + stm_info, + true, + false, + stm_info_sync_verify, + NULL, + } +}; + +/* to check and return command index of stm_test_command_list[] + * Input: + * - command_name: null terminated string of STM test command_name + * Return: + * - 0 or positive: index of command_name + * - negative value: error + */ +int check_command_index(const char* command_name) +{ + int index = -1; + int total_commands = 0; + + total_commands = (int) (sizeof(stm_test_command_list)/sizeof(command_list)); + + for(index = 0; index < total_commands; index ++) { + if(!strcmp(command_name, stm_test_command_list[index].command_name)) { + TDBG("command match found, index=%d, command_name=%s\n", + index, command_name); + return index; + } + } + + /* in case there is no match, return an error. */ + index = -1; + TDBG("no command match. command_name=%s\n", command_name); + return index; +} + +/* to create one STM channel + * Input: + * - param_num: total number of parameters, incl. command_name, in param_array + * - param_array: an char string array to host all parameters, w/ command_name + * being the first. + * Return: + * - 0: success + * - negartive value: error + */ +int stm_create_channel(int param_num, char** param_array, command_result_type* ptr_command_result) +{ + int ret = -1; + char shell_command[MAX_SHELL_COMMAND_LINE_SIZE]; + + TDBG("In %s()\n", __FUNCTION__); + + /* check validity of input parameters */ + if(param_num != 2) { + TDBG("Invalid parameter numbers in %s.\n", __FUNCTION__); + return ret; + } + + /* compose a shell command */ + ret = snprintf(shell_command, MAX_SHELL_COMMAND_LINE_SIZE, + "echo -n \"user %s\\0\" > %srequest", param_array[1], DEBUGFS_STM); + if( ret >= MAX_SHELL_COMMAND_LINE_SIZE ) { + /* a return value of size or more means that the output + * was truncated. */ + TDBG("Command line too long. %d\n", ret); + printf("Command line too long. Try to use shorter strings.\n"); + return -ret; + } + + /* send this command to shell */ + ret = system(shell_command); + TDBG("system(\"%s\") returns %d, RAW ret = 0x%x\n", shell_command, WEXITSTATUS(ret), ret); + if( ret == -1 ) { + printf("system() returns error %d.", ret); + return ret; + } + switch( WEXITSTATUS(ret) ) { + case 0: + ptr_command_result->command_execution_result = COMMAND_EXEC_SUCCESS; + break; + case 2: + + /* TODO + * more checks about error conditions + * + * 2 means: sh: cannot create /sys/kernel/debug/stm/request: Permission denied system(echo -n -e "user xx" > /sys/kernel/debug/stm/request) returns 2. + */ + ptr_command_result->command_execution_result = COMMAND_EXEC_FAILURE; + break; + default: + ptr_command_result->command_execution_result = COMMAND_EXEC_FAILURE; + break; + } + + return WEXITSTATUS(ret); +} + + +/* to verify the creation of one STM channel + * Input: + * - param_num: total number of parameters, incl. command_name, in param_array + * - param_array: an char string array to host all parameters, w/ command_name + * being the first. + * Return: + * - 0: success + * - -1: only , no _config; + * - -2: only _config, no ; + * - -3: neither of and _config exist; + * - negartive value: error, other + */ +int stm_create_channel_sync_verify(int param_num, char** param_array, command_result_type* ptr_command_result) +{ + int ret = -1; + bool exist_channel_name = false; + bool exist_channel_config = false; + char channel_config_name[MAX_CONFIG_NAME_LENGTH]; + char* channel_name = param_array[1]; + + TDBG("In %s: channel_name is %s.\n", __FUNCTION__, channel_name); + + /* set verification result as failure */ + ptr_command_result->sync_veri_result = SYNC_VERIFICATION_FAILURE; + + /* to check two new nodes under stm/: and _config */ + if (search_file(DEBUGFS_STM, channel_name) == 1) + exist_channel_name = true; + + ret = snprintf(channel_config_name, MAX_CONFIG_NAME_LENGTH, "%s_config", channel_name); + /* check if truncated */ + if (ret >= MAX_CONFIG_NAME_LENGTH ) { + printf("config file name exceeds maximum allowed length %d. %s.", + MAX_CONFIG_NAME_LENGTH, channel_name); + goto verify_result; + } + if (search_file(DEBUGFS_STM, channel_config_name) == 1) + exist_channel_config = true; + +verify_result: + if (exist_channel_name) { + if (exist_channel_config) { + ptr_command_result->sync_veri_result = SYNC_VERIFICATION_SUCCESS; + return 0; + } + else + return -1; + } else { + if (exist_channel_config) + return -2; + else + return -3; + } + + return -4; /* should never been here*/ +} + +/* to get general STM information by reading /stm/request + * Input: + * - param_num: total number of parameters, incl. command_name, in param_array + * - param_array: an char string array to host all parameters, w/ command_name + * being the first. + * Return: + * - 0: success + * - -1: failure + */ +int stm_info(int param_num, char** param_array, command_result_type* ptr_command_result) +{ + int ret = -1; + char request_filename[MAX_CONFIG_NAME_LENGTH] = ""; + unsigned char* stm_information; + FILE* fd; + int offset = 0; + + /* compose the filename */ + ret = snprintf(request_filename, MAX_CONFIG_NAME_LENGTH, "%srequest", DEBUGFS_STM); + if (ret >= MAX_CONFIG_NAME_LENGTH) { + TDBG("STM request fileanme is longer than %d byte in length. Which should not happen.\n", MAX_CONFIG_NAME_LENGTH); + return -1; + } + + /* open /request */ + fd = fopen(request_filename, "rb"); + + /* allocate memory for file reading */ + stm_information = (unsigned char *)malloc(MAX_SIZE_STM_REQUEST); + if (stm_information == NULL) { + printf("Memory allocation error in func: %s\n", __FUNCTION__); + return -1; + } + memset(stm_information, '\0', MAX_SIZE_STM_REQUEST); + + /* read file contents */ + ret = fread(stm_information, sizeof(unsigned char), MAX_SIZE_STM_REQUEST, fd); + TDBG("STM request %s file length: %d byte\n", request_filename, ret); + + if (!feof(fd)) { + printf("STM request reading returns more than %d bytes. Need to modify the source code to fix this.\n", MAX_SIZE_STM_REQUEST); + return -1; + } + + /* for debugging purpose only, dump file contents */ + TDBG("Dump of STM request file:\n"); + { + int i; + unsigned char* c; + for(i = 0, c = stm_information; i < ret; i ++, c ++) { + TDBG("%c", *c); + } + TDBG("\n"); + } + + /* link the memory space to private_data */ + ptr_command_result->private_data = stm_information; + return 0; +} + +int stm_info_sync_verify() +{ + return 0; +} + +static int command_sequencial_count = 0; /* to record total number of commands executed */ + +int main(int argc, char** argv) +{ + int ret = 0; + bool succ = true; + int cmd_index = -1; + command_list* current_command = NULL; + command_result_type current_command_result; + +/* + pthread_mutex_init(&mux, NULL); + pthread_mutex_lock(&mux); + TDBG("pthread_mutex testing.\n"); + pthread_mutex_unlock(&mux); +*/ + + /* check command line information */ + if (argc == 1) { + TDBG("Test commands come from standard input.\n"); + /* read test commands from standard input */ + /* TODO */ + return ret; + } + + /* check index of test command */ + cmd_index = check_command_index(argv[1]); + if (cmd_index < 0) { + printf("Invaild test command. Type in \" %s help\" to get guidance.\n", argv[0]); + return ret; + } + + current_command = &stm_test_command_list[cmd_index]; + + /* initialize current_command_result */ + INIT_COMMAND_RESULT(¤t_command_result); + current_command_result.current_command = &stm_test_command_list[cmd_index]; + current_command_result.sequencial_id = command_sequencial_count; + + /* increase the global command seq count by 1 */ + command_sequencial_count ++; + + /* make and send shell command */ + (* current_command->command_consumer_callback)(argc - 1, argv + 1, ¤t_command_result); + + /* to call sync_verification API if proper */ + if (current_command->is_sync == true && current_command->sync_verification_callback != NULL) { + TDBG("to call sync_verification API.\n"); + (* current_command->sync_verification_callback)(argc - 1, argv +1, ¤t_command_result); + } + + /* to call async_verification API if proper */ + if (current_command->is_async == true && current_command->async_verification_callback != NULL) { + TDBG("to call async_verification API.\n"); + (* current_command->async_verification_callback)(); + } + + /* to record the command result */ + /* TODO */ + + /* to free memory before exit */ + /* TODO */ + if (current_command_result.private_data != NULL) { + /* TODO: double check here. what if the private_data is not one single block allocated by malloc? should we define a command specific private_data freeing API? */ + free(current_command_result.private_data); + } + + return ret; +} + diff --git a/test_commands.h b/test_commands.h new file mode 100644 index 0000000..e7498d0 --- /dev/null +++ b/test_commands.h @@ -0,0 +1,72 @@ +/* ------------------------------------------------------------------ + * test_commands.h + * Defines commands and structures of testing. + * ----------------------------------------------------------------*/ + +#ifndef STM_TEST_COMMANDS_H +#define STM_TEST_COMMANDS_H + +#include +#include + +#define STM_TEST_DEBUG +#ifdef STM_TEST_DEBUG +#define TDBG printf +#else +#define TDBG +#endif + +#define MAX_COMMAND_NAME_LENGTH (16) +#define MAX_SHELL_COMMAND_LINE_SIZE (100) +#define MAX_CONFIG_NAME_LENGTH (100) +#define MAX_SIZE_STM_REQUEST (4096) /* maximum 4k for a read of /stm/request + * should be enough, and is double checked in code + * as well. */ + +/* external functions */ +extern int stm_create_channel(); +extern int stm_create_channel_sync_verify(); +extern int stm_info(); +extern int stm_info_sync_verify(); +extern int search_file(const char* path, const char* name); + +typedef struct command_list { + char command_name[MAX_COMMAND_NAME_LENGTH]; + int (*command_consumer_callback) (); + bool is_sync; + bool is_async; + int (*sync_verification_callback) (); + int (*async_verification_callback) (); +} command_list; + +typedef struct command_result_type { + command_list* current_command; /* pointer to current command in command_list */ + int sequencial_id; /* command sequencial id */ + int command_execution_result; /* this is direct result returned by command execution */ + int sync_veri_result; /* this is result returned by sync verificaiton callback */ + int async_veri_result; /* this is result returned by async verification callback */ + void* private_data; /* this is private data, which is meaningful to specific command */ +} command_result_type; + +#define COMMAND_EXEC_SUCCESS (0) +#define COMMAND_EXEC_FAILURE (-1) +#define VERIFICATION_FAILURE (-100) +#define VERIFICATION_SUCCESS (0) +#define SYNC_VERIFICATION_SUCCESS VERIFICATION_SUCCESS +#define ASYNC_VERIFICATION_SUCCESS VERIFICATION_SUCCESS +#define SYNC_VERIFICATION_FAILURE VERIFICATION_FAILURE +#define ASYNC_VERIFICATION_FAILURE VERIFICATION_FAILURE + + +static inline void INIT_COMMAND_RESULT(command_result_type *ptr_command_result) +{ + ptr_command_result->current_command = NULL; + ptr_command_result->sequencial_id = -1; + ptr_command_result->command_execution_result = COMMAND_EXEC_FAILURE; + ptr_command_result->sync_veri_result = SYNC_VERIFICATION_FAILURE; + ptr_command_result->async_veri_result = ASYNC_VERIFICATION_FAILURE; + ptr_command_result->private_data = NULL; +} + + +#endif /* STM_TEST_COMMANDS_H */ -- cgit v1.2.3