summaryrefslogtreecommitdiffstats
path: root/cpukit/libmisc/shell/shell_script.c
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>2008-03-05 02:49:35 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>2008-03-05 02:49:35 +0000
commita3ddb08bec11871f6e83bb7aaa53a17a4ea5309c (patch)
tree7a77642c272052b03260156dc5062d23f16e3a35 /cpukit/libmisc/shell/shell_script.c
parentNew. (diff)
downloadrtems-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.c327
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;
+}
+