summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Harkin <ryan.harkin@linaro.org>2012-05-25 08:36:24 +0000
committerRyan Harkin <ryan.harkin@linaro.org>2012-05-25 08:36:24 +0000
commit05488cad0e381dc10f54d6d9909ab7eab30f262e (patch)
treea627a02346562fcf4a29f56c4eee8fcd7f0b535c
Initial commitHEADmaster
-rw-r--r--Makefile15
-rw-r--r--debug_stm/my0
-rw-r--r--debug_stm/my_config0
-rw-r--r--debug_stm/request1
-rw-r--r--fileop.c106
-rw-r--r--main.c326
-rw-r--r--test_commands.h72
7 files changed, 520 insertions, 0 deletions
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
--- /dev/null
+++ b/debug_stm/my
diff --git a/debug_stm/my_config b/debug_stm/my_config
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/debug_stm/my_config
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 <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#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 <name> 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 <name> in directory <path>
+ * 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 <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(&current_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, &current_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, &current_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 <stdio.h>
+#include <stdbool.h>
+
+#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 <debugfs>/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 */