diff options
Diffstat (limited to 'main.c')
-rw-r--r-- | main.c | 326 |
1 files changed, 326 insertions, 0 deletions
@@ -0,0 +1,326 @@ +/* Test application of STM Framework and driver + * + */ + +#include <stdio.h> +#include <stdbool.h> +#include <string.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <dirent.h> +#include <pthread.h> + +#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 <channel_name>, no <channel_name>_config; + * - -2: only <channel_name>_config, no <channel_name>; + * - -3: neither of <channel_name> and <channel_name>_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/: <channel_name> and <channel_name>_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 <debugfs>/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 <debugfs>/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; +} + |