diff options
author | Joel Sherrill <joel.sherrill@OARcorp.com> | 2008-03-05 02:49:35 +0000 |
---|---|---|
committer | Joel Sherrill <joel.sherrill@OARcorp.com> | 2008-03-05 02:49:35 +0000 |
commit | a3ddb08bec11871f6e83bb7aaa53a17a4ea5309c (patch) | |
tree | 7a77642c272052b03260156dc5062d23f16e3a35 /cpukit/libmisc/shell/shell_script.c | |
parent | New. (diff) | |
download | rtems-a3ddb08bec11871f6e83bb7aaa53a17a4ea5309c.tar.bz2 |
2008-03-04 Joel Sherrill <joel.sherrill@oarcorp.com>
* libmisc/Makefile.am, libmisc/shell/main_cp.c,
libmisc/shell/main_cpuuse.c, libmisc/shell/main_date.c,
libmisc/shell/main_mallocinfo.c, libmisc/shell/main_netstats.c,
libmisc/shell/main_perioduse.c, libmisc/shell/main_stackuse.c,
libmisc/shell/main_wkspaceinfo.c, libmisc/shell/print_heapinfo.c,
libmisc/shell/shell.c, libmisc/shell/shell.h,
libmisc/shell/shell_makeargs.c, libmisc/shell/shellconfig.c,
libmisc/shell/shellconfig.h, libmisc/shell/write_file.c: Add initial
capability to automatically execute a script from the filesystem. Add
echo command from NetBSD and sleep command.
* libmisc/shell/main_echo.c, libmisc/shell/main_sleep.c,
libmisc/shell/shell_script.c: New files.
Diffstat (limited to 'cpukit/libmisc/shell/shell_script.c')
-rw-r--r-- | cpukit/libmisc/shell/shell_script.c | 327 |
1 files changed, 327 insertions, 0 deletions
diff --git a/cpukit/libmisc/shell/shell_script.c b/cpukit/libmisc/shell/shell_script.c new file mode 100644 index 0000000000..a38d2aa72d --- /dev/null +++ b/cpukit/libmisc/shell/shell_script.c @@ -0,0 +1,327 @@ +/* + * Shell Script Invocation + * + * Pseudo-code from Chris Johns, implemented and debugged + * by Joel Sherrill. + * + * COPYRIGHT (c) 1989-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <inttypes.h> +#include <sys/types.h> +#include <unistd.h> +#include <getopt.h> + +#include <rtems.h> +#include <rtems/shell.h> +#include "internal.h" + +static void rtems_shell_joel_usage() +{ + printf( + "joel [args] where args may be:\n" + " -o FILE output file (default=stdout)\n" + " -p PRIORITY task priority\n" + " -s SIZE task stack size\n" + " -t NAME task name\n" + ); +} + +int rtems_shell_main_decho( + int argc, + char **argv +) +{ + int i; + + for (i=0 ; i<argc ; i++ ) + printf( "argv[%d] = -%s-\n", i, argv[i] ); + return 0; +} + +static int findOnPATH( + const char *userScriptName, + char *scriptFile +) +{ + /* + * If the user script name starts with a / assume it is a fully + * qualified path name and just use it. + */ + if ( userScriptName[0] == '/' ) { + strcpy( scriptFile, userScriptName ); + return 0; + } + + /* + * For now, the provided name is just turned into a fully + * qualified path name and used. There is no attempt to + * search along a path for it. + */ + + getcwd( scriptFile, PATH_MAX ); + /* XXX should use strncat but what is the limit? */ + strcat( scriptFile, "/" ); + strcat( scriptFile, userScriptName ); + return 0; + +#if 0 + /* + * Does the command (argv[0]) contain a path ?, i.e. starts with + * '.' or contains a '/'? + */ + /* TODO: Add concept of PATH */ + if (!contains_path) { + /* check PATH environment variable */ + for (path_part = PATH; path_part; skip to ':') + { + } + if (not found) + return -1; + } +#endif +} + +int rtems_shell_main_joel( + int argc, + char **argv +) +{ + int option; + int sc; + int verbose = 0; + char *taskName = "JOEL"; + uint32_t stackSize = RTEMS_MINIMUM_STACK_SIZE * 10; + rtems_task_priority taskPriority = 20; + char *outputFile = "stdout"; + rtems_status_code result; + char scriptFile[PATH_MAX]; + struct getopt_data getopt_reent; + + while ( (option = getopt_r( argc, argv, "o:p:s:t:v", &getopt_reent)) != -1 ) { + switch ((char)option) { + case 'o': + outputFile = getopt_reent.optarg; + break; + case 'p': + taskPriority = rtems_shell_str2int(getopt_reent.optarg); + break; + case 's': + stackSize = rtems_shell_str2int(getopt_reent.optarg); + break; + case 't': + taskName = getopt_reent.optarg; + break; + case 'v': + verbose = 1; + break; + case '?': + default: + rtems_shell_joel_usage(); + return -1; + } + } + + if ( verbose ) { + fprintf( stderr, + "outputFile: %s\n" + "taskPriority: %" PRId32 "\n" + "stackSize: %" PRId32 "\n" + "taskName: %s\n", + outputFile, + taskPriority, + stackSize, + taskName + ); + } + + /* + * Verify there is a script name past the end of the arguments. + * Preincrement to skip program name. + */ + if ( getopt_reent.optind >= argc ) { + fprintf( stderr, "Shell: No script to execute\n" ); + return -1; + } + + /* + * Find script on the path. + * + * NOTE: It is terrible that this is done twice but it + * seems to be the most expedient thing. + */ + sc = findOnPATH( argv[getopt_reent.optind], scriptFile ); + if ( sc ) { + fprintf( stderr, "%s not found on PATH\n", argv[0] ); + return -1; + } + + /* fprintf( stderr, "SCRIPT: -%s-\n", scriptFile ); */ + + /* + * I assume that argv[optind...] will have the arguments to + * the shell script. But that remains to be implemented. + */ + + /* + * Run the script + */ + result = rtems_shell_script( + taskName, /* the name of the task */ + stackSize, /* stack size */ + taskPriority, /* task priority */ + scriptFile, /* the script file */ + outputFile, /* where to redirect the script */ + 0, /* run once and exit */ + 1 /* we will wait */ + ); + if (result) + return -1; + return 0; +} + +rtems_shell_cmd_t rtems_shell_JOEL_Command = { + "joel", /* name */ + "joel [args] SCRIPT", /* usage */ + "misc", /* topic */ + rtems_shell_main_joel, /* command */ + NULL, /* alias */ + NULL /* next */ +}; + +/* + * This is a helper function which takes a command as arguments + * which has not been located as a built-in command and attempts + * to find something in the filesystem with the same name that + * appears to be a shell script. + */ +int rtems_shell_script_file( + int argc, + char *argv[] +) +{ + #define FIRST_LINE_LENGTH 128 + #define SCRIPT_ARGV_LIMIT 32 + char scriptFile[PATH_MAX]; + char *scriptHead; + char scriptHeadBuffer[FIRST_LINE_LENGTH]; + int sc; + FILE *script; + size_t length; + int scriptArgc; + char *scriptArgv[SCRIPT_ARGV_LIMIT]; + + /* + * Clear argv pointer array + */ + for ( scriptArgc=0 ; scriptArgc<SCRIPT_ARGV_LIMIT ; scriptArgc++ ) + scriptArgv[scriptArgc] = NULL; + + /* + * Find argv[0] on the path + */ + sc = findOnPATH( argv[0], scriptFile ); + if ( sc ) { + fprintf( stderr, "%s not found on PATH\n", argv[0] ); + return -1; + } + + /* + * Open the file so we can see if it looks like a script. + */ + script = fopen( scriptFile, "r" ); + if ( !script ) { + fprintf( stderr, "%s: Unable to open %s\n", argv[0], scriptFile ); + return -1; + } + + /* + * Is the script OK to run? + * Verify the current user has permission to execute it. + * + * NOTE: May not work on all file systems + */ + sc = access( scriptFile, X_OK ); + if ( sc ) { + fprintf( stderr, "Unable to execute %s\n", scriptFile ); + fclose( script ); + return -1; + } + + /* + * Try to read the first line from the potential script file + */ + scriptHead = fgets(scriptHeadBuffer, FIRST_LINE_LENGTH, script); + if ( !scriptHead ) { + fprintf( + stderr, "%s: Unable to read first line of %s\n", argv[0], scriptFile ); + fclose( script ); + return -1; + } + + fclose(script); + + length = strnlen(scriptHead, FIRST_LINE_LENGTH); + scriptHead[length - 1] = '\0'; + + /* fprintf( stderr, "FIRST LINE: -%s-\n", scriptHead ); */ + + /* + * Verify the name of the "shell" is joel. This means + * the line starts with "#! joel". + */ + if (strncmp("#! joel", scriptHead, 7) != 0) { + fprintf( stderr, "%s: Not a joel script %s\n", argv[0], scriptFile ); + return -1; + } + + /* + * Do not worry about search path further. We have found the + * script, it is executable, and we have successfully read the + * first line and found out it is a script. + */ + + /* + * Check for arguments in fist line of the script. This changes + * how the shell task is run. + */ + + sc = rtems_shell_make_args( + &scriptHead[3], + &scriptArgc, + scriptArgv, + SCRIPT_ARGV_LIMIT - 1 + ); + if ( sc ) { + fprintf( + stderr, "%s: Error parsing joel arguments %s\n", argv[0], scriptFile ); + return -1; + } + + scriptArgv[ scriptArgc++ ] = scriptFile; + + /* + * TODO: How do we pass arguments from here to the script? + * At this point, it doesn't matter because we don't + * have any way for a shell script to access them. + */ + return rtems_shell_main_joel( scriptArgc, scriptArgv ); + + return 0; +} + |