/* 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; }