summaryrefslogtreecommitdiffstats
path: root/cpukit/libmisc/shell/shell.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/libmisc/shell/shell.c')
-rw-r--r--cpukit/libmisc/shell/shell.c987
1 files changed, 987 insertions, 0 deletions
diff --git a/cpukit/libmisc/shell/shell.c b/cpukit/libmisc/shell/shell.c
new file mode 100644
index 0000000000..bcc146731b
--- /dev/null
+++ b/cpukit/libmisc/shell/shell.c
@@ -0,0 +1,987 @@
+/*
+ *
+ * Instantatiate a new terminal shell.
+ *
+ * Author:
+ *
+ * WORK: fernando.ruiz@ctv.es
+ * HOME: correo@fernando-ruiz.com
+ *
+ * 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 <time.h>
+
+#include <rtems.h>
+#include <rtems/error.h>
+#include <rtems/libio.h>
+#include <rtems/libio_.h>
+#include <rtems/system.h>
+#include <rtems/shell.h>
+#include <rtems/shellconfig.h>
+#include <rtems/console.h>
+#include "internal.h"
+
+#include <termios.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <pwd.h>
+
+rtems_shell_env_t rtems_global_shell_env = {
+ .magic = rtems_build_name('S', 'E', 'N', 'V'),
+ .devname = CONSOLE_DEVICE_NAME,
+ .taskname = "SHGL",
+ .exit_shell = false,
+ .forever = true,
+ .errorlevel = -1,
+ .echo = false,
+ .cwd = "/",
+ .input = NULL,
+ .output = NULL,
+ .output_append = false,
+ .wake_on_end = RTEMS_ID_NONE,
+ .login_check = NULL
+};
+
+rtems_shell_env_t *rtems_current_shell_env = &rtems_global_shell_env;
+
+/*
+ * Initialize the shell user/process environment information
+ */
+rtems_shell_env_t *rtems_shell_init_env(
+ rtems_shell_env_t *shell_env_p
+)
+{
+ rtems_shell_env_t *shell_env;
+
+ shell_env = malloc(sizeof(rtems_shell_env_t));
+ if ( !shell_env )
+ return NULL;
+ if ( !shell_env_p ) {
+ *shell_env = rtems_global_shell_env;
+ } else {
+ *shell_env = *shell_env_p;
+ }
+ shell_env->taskname = NULL;
+
+ return shell_env;
+}
+
+/*
+ * Completely free a shell_env_t and all associated memory
+ */
+void rtems_shell_env_free(
+ void *ptr
+)
+{
+ rtems_shell_env_t *shell_env;
+ shell_env = (rtems_shell_env_t *) ptr;
+
+ if ( !ptr )
+ return;
+
+ if ( shell_env->input )
+ free((void *)shell_env->input);
+ if ( shell_env->output )
+ free((void *)shell_env->output);
+ free( ptr );
+}
+
+/*
+ * Get a line of user input with modest features
+ */
+int rtems_shell_line_editor(
+ char *cmds[],
+ int count,
+ int size,
+ const char *prompt,
+ FILE *in,
+ FILE *out
+)
+{
+ unsigned int extended_key;
+ int c;
+ int col;
+ int last_col;
+ int output;
+ char line[size];
+ char new_line[size];
+ int up;
+ int cmd = -1;
+ int inserting = 1;
+
+ output = (out && isatty(fileno(in)));
+
+ col = last_col = 0;
+
+ tcdrain(fileno(in));
+ if (out)
+ tcdrain(fileno(out));
+
+ if (output && prompt)
+ fprintf(out, "\r%s", prompt);
+
+ line[0] = 0;
+ new_line[0] = 0;
+
+ for (;;) {
+
+ if (output)
+ fflush(out);
+
+ extended_key = rtems_shell_getchar(in);
+
+ if (extended_key == EOF)
+ return -2;
+
+ c = extended_key & RTEMS_SHELL_KEYS_NORMAL_MASK;
+
+ /*
+ * Make the extended_key usable as a boolean.
+ */
+ extended_key &= ~RTEMS_SHELL_KEYS_NORMAL_MASK;
+
+ up = 0;
+
+ if (extended_key)
+ {
+ switch (c)
+ {
+ case RTEMS_SHELL_KEYS_END:
+ if (output)
+ fprintf(out, "%s", line + col);
+ col = (int) strlen (line);
+ break;
+
+ case RTEMS_SHELL_KEYS_HOME:
+ if (output) {
+ if (prompt)
+ fprintf(out,"\r%s", prompt);
+ }
+ col = 0;
+ break;
+
+ case RTEMS_SHELL_KEYS_LARROW:
+ if (col > 0)
+ {
+ col--;
+ if (output)
+ fputc('\b', out);
+ }
+ break;
+
+ case RTEMS_SHELL_KEYS_RARROW:
+ if ((col < size) && (line[col] != '\0'))
+ {
+ if (output)
+ fprintf(out, "%c", line[col]);
+ col++;
+ }
+ break;
+
+ case RTEMS_SHELL_KEYS_UARROW:
+ if ((cmd >= (count - 1)) || (strlen(cmds[cmd + 1]) == 0)) {
+ if (output)
+ fputc('\x7', out);
+ break;
+ }
+
+ up = 1;
+
+ /* drop through */
+ case RTEMS_SHELL_KEYS_DARROW:
+
+ {
+ int last_cmd = cmd;
+ int clen = strlen (line);
+
+ if (prompt)
+ clen += strlen(prompt);
+
+ if (up) {
+ cmd++;
+ } else {
+ if (cmd < 0) {
+ if (output)
+ fprintf(out, "\x7");
+ break;
+ }
+ else
+ cmd--;
+ }
+
+ if ((last_cmd < 0) || (strcmp(cmds[last_cmd], line) != 0))
+ memcpy (new_line, line, size);
+
+ if (cmd < 0)
+ memcpy (line, new_line, size);
+ else
+ memcpy (line, cmds[cmd], size);
+
+ col = strlen (line);
+
+ if (output) {
+ fprintf(out,"\r%*c", clen, ' ');
+ fprintf(out,"\r%s%s", prompt, line);
+ }
+ }
+ break;
+
+ case RTEMS_SHELL_KEYS_DEL:
+ if (line[col] != '\0')
+ {
+ int end;
+ int bs;
+ strcpy (&line[col], &line[col + 1]);
+ if (output) {
+ fprintf(out,"\r%s%s ", prompt, line);
+ end = (int) strlen (line);
+ for (bs = 0; bs < ((end - col) + 1); bs++)
+ fputc('\b', out);
+ }
+ }
+ break;
+
+ case RTEMS_SHELL_KEYS_INS:
+ inserting = inserting ? 0 : 1;
+ break;
+ }
+ }
+ else
+ {
+ switch (c)
+ {
+ case 1:/*Control-a*/
+ if (output) {
+ if (prompt)
+ fprintf(out,"\r%s", prompt);
+ }
+ col = 0;
+ break;
+
+ case 5:/*Control-e*/
+ if (output)
+ fprintf(out, "%s", line + col);
+ col = (int) strlen (line);
+ break;
+
+ case 11:/*Control-k*/
+ if (line[col]) {
+ if (output) {
+ int end = strlen(line);
+ int bs;
+ fprintf(out,"%*c", end - col, ' ');
+ for (bs = 0; bs < (end - col); bs++)
+ fputc('\b', out);
+ }
+ line[col] = '\0';
+ }
+ break;
+
+ case 0x04:/*Control-d*/
+ if (strlen(line))
+ break;
+ case EOF:
+ if (output)
+ fputc('\n', out);
+ return -2;
+
+ case '\f':
+ if (output) {
+ int end;
+ int bs;
+ fputc('\f',out);
+ fprintf(out,"\r%s%s", prompt, line);
+ end = (int) strlen (line);
+ for (bs = 0; bs < (end - col); bs++)
+ fputc('\b', out);
+ }
+ break;
+
+ case '\b':
+ case '\x7f':
+ if (col > 0)
+ {
+ int bs;
+ col--;
+ strcpy (line + col, line + col + 1);
+ if (output) {
+ fprintf(out,"\b%s \b", line + col);
+ for (bs = 0; bs < ((int) strlen (line) - col); bs++)
+ fputc('\b', out);
+ }
+ }
+ break;
+
+ case '\n':
+ case '\r':
+ {
+ /*
+ * Process the command.
+ */
+ if (output)
+ fprintf(out,"\n");
+
+ /*
+ * Only process the command if we have a command and it is not
+ * repeated in the history.
+ */
+ if (strlen(line) == 0) {
+ cmd = -1;
+ } else {
+ if ((cmd < 0) || (strcmp(line, cmds[cmd]) != 0)) {
+ if (count > 1)
+ memmove(cmds[1], cmds[0], (count - 1) * size);
+ memmove (cmds[0], line, size);
+ cmd = 0;
+ }
+ }
+ }
+ return cmd;
+
+ default:
+ if ((col < (size - 1)) && (c >= ' ') && (c <= '~')) {
+ int end = strlen (line);
+ if (inserting && (col < end) && (end < size)) {
+ int ch, bs;
+ for (ch = end + 1; ch > col; ch--)
+ line[ch] = line[ch - 1];
+ if (output) {
+ fprintf(out, "%s", line + col);
+ for (bs = 0; bs < (end - col + 1); bs++)
+ fputc('\b', out);
+ }
+ }
+ line[col++] = c;
+ if (col > end)
+ line[col] = '\0';
+ if (output)
+ fputc(c, out);
+ }
+ break;
+ }
+ }
+ }
+ return -2;
+}
+
+/* ----------------------------------------------- *
+ * - The shell TASK
+ * Poor but enough..
+ * TODO: Redirection. Tty Signals. ENVVARs. Shell language.
+ * ----------------------------------------------- */
+
+void rtems_shell_init_issue(void)
+{
+ static bool issue_inited=false;
+ struct stat buf;
+
+ if (issue_inited)
+ return;
+ issue_inited = true;
+
+ /* dummy call to init /etc dir */
+ getpwnam("root");
+
+ if (stat("/etc/issue",&buf)) {
+ rtems_shell_write_file("/etc/issue",
+ "\n"
+ "Welcome to @V\\n"
+ "Login into @S\\n");
+ }
+
+ if (stat("/etc/issue.net",&buf)) {
+ rtems_shell_write_file("/etc/issue.net",
+ "\n"
+ "Welcome to %v\n"
+ "running on %m\n");
+ }
+}
+
+static bool rtems_shell_login(FILE * in,FILE * out) {
+ FILE *fd;
+ int c;
+ time_t t;
+
+ rtems_shell_init_issue();
+ setuid(0);
+ setgid(0);
+ rtems_current_user_env->euid =
+ rtems_current_user_env->egid =0;
+
+ if (out) {
+ if ((rtems_current_shell_env->devname[5]!='p')||
+ (rtems_current_shell_env->devname[6]!='t')||
+ (rtems_current_shell_env->devname[7]!='y')) {
+ fd = fopen("/etc/issue","r");
+ if (fd) {
+ while ((c=fgetc(fd))!=EOF) {
+ if (c=='@') {
+ switch(c=fgetc(fd)) {
+ case 'L':
+ fprintf(out,"%s",rtems_current_shell_env->devname);
+ break;
+ case 'B':
+ fprintf(out,"0");
+ break;
+ case 'T':
+ case 'D':
+ time(&t);
+ fprintf(out,"%s",ctime(&t));
+ break;
+ case 'S':
+ fprintf(out,"RTEMS");
+ break;
+ case 'V':
+ fprintf(out,"%s\n%s",_RTEMS_version, _Copyright_Notice);
+ break;
+ case '@':
+ fprintf(out,"@");
+ break;
+ default :
+ fprintf(out,"@%c",c);
+ break;
+ }
+ } else if (c=='\\') {
+ switch(c=fgetc(fd)) {
+ case '\\': fprintf(out,"\\"); break;
+ case 'b': fprintf(out,"\b"); break;
+ case 'f': fprintf(out,"\f"); break;
+ case 'n': fprintf(out,"\n"); break;
+ case 'r': fprintf(out,"\r"); break;
+ case 's': fprintf(out," "); break;
+ case 't': fprintf(out,"\t"); break;
+ case '@': fprintf(out,"@"); break;
+ }
+ } else {
+ fputc(c,out);
+ }
+ }
+ fclose(fd);
+ }
+ } else {
+ fd = fopen("/etc/issue.net","r");
+ if (fd) {
+ while ((c=fgetc(fd))!=EOF) {
+ if (c=='%') {
+ switch(c=fgetc(fd)) {
+ case 't':
+ fprintf(out,"%s",rtems_current_shell_env->devname);
+ break;
+ case 'h':
+ fprintf(out,"0");
+ break;
+ case 'D':
+ fprintf(out," ");
+ break;
+ case 'd':
+ time(&t);
+ fprintf(out,"%s",ctime(&t));
+ break;
+ case 's':
+ fprintf(out,"RTEMS");
+ break;
+ case 'm':
+ fprintf(out,"(" CPU_NAME "/" CPU_MODEL_NAME ")");
+ break;
+ case 'r':
+ fprintf(out,_RTEMS_version);
+ break;
+ case 'v':
+ fprintf(out,"%s\n%s",_RTEMS_version,_Copyright_Notice);
+ break;
+ case '%':fprintf(out,"%%");
+ break;
+ default:
+ fprintf(out,"%%%c",c);
+ break;
+ }
+ } else {
+ fputc(c,out);
+ }
+ }
+ fclose(fd);
+ }
+ }
+ }
+
+ return rtems_shell_login_prompt(
+ in,
+ out,
+ rtems_current_shell_env->devname,
+ rtems_current_shell_env->login_check
+ );
+}
+
+#if defined(SHELL_DEBUG)
+void rtems_shell_print_env(
+ rtems_shell_env_t * shell_env
+)
+{
+ if ( !shell_env ) {
+ printk( "shell_env is NULL\n" );
+ return;
+ }
+ printk( "shell_env=%p\n"
+ "shell_env->magic=0x%08x\t"
+ "shell_env->devname=%s\n"
+ "shell_env->taskname=%s\t"
+ "shell_env->exit_shell=%d\t"
+ "shell_env->forever=%d\n",
+ shell_env->magic,
+ shell_env->devname,
+ ((shell_env->taskname) ? shell_env->taskname : "NOT SET"),
+ shell_env->exit_shell,
+ shell_env->forever
+ );
+}
+#endif
+
+rtems_task rtems_shell_task(rtems_task_argument task_argument)
+{
+ rtems_shell_env_t *shell_env = (rtems_shell_env_t*) task_argument;
+ rtems_id wake_on_end = shell_env->wake_on_end;
+ rtems_shell_main_loop( shell_env );
+ if (wake_on_end != RTEMS_INVALID_ID)
+ rtems_event_send (wake_on_end, RTEMS_EVENT_1);
+ rtems_task_delete( RTEMS_SELF );
+}
+
+#define RTEMS_SHELL_MAXIMUM_ARGUMENTS (128)
+#define RTEMS_SHELL_CMD_SIZE (128)
+#define RTEMS_SHELL_CMD_COUNT (32)
+#define RTEMS_SHELL_PROMPT_SIZE (128)
+
+bool rtems_shell_main_loop(
+ rtems_shell_env_t *shell_env_arg
+)
+{
+ rtems_shell_env_t *shell_env;
+ rtems_shell_cmd_t *shell_cmd;
+ rtems_status_code sc;
+ struct termios term;
+ struct termios previous_term;
+ char *prompt = NULL;
+ int cmd;
+ int cmd_count = 1; /* assume a script and so only 1 command line */
+ char *cmds[RTEMS_SHELL_CMD_COUNT];
+ char *cmd_argv;
+ int argc;
+ char *argv[RTEMS_SHELL_MAXIMUM_ARGUMENTS];
+ bool result = true;
+ bool input_file = false;
+ int line = 0;
+ FILE *stdinToClose = NULL;
+ FILE *stdoutToClose = NULL;
+
+ rtems_shell_initialize_command_set();
+
+ shell_env =
+ rtems_current_shell_env = rtems_shell_init_env( shell_env_arg );
+
+ /*
+ * @todo chrisj
+ * Remove the use of task variables. Change to have a single
+ * allocation per shell and then set into a notepad register
+ * in the TCB. Provide a function to return the pointer.
+ * Task variables are a virus to embedded systems software.
+ */
+ sc = rtems_task_variable_add(
+ RTEMS_SELF,
+ (void*)&rtems_current_shell_env,
+ rtems_shell_env_free
+ );
+ if (sc != RTEMS_SUCCESSFUL) {
+ rtems_error(sc,"rtems_task_variable_add(current_shell_env):");
+ return false;
+ }
+
+ setuid(0);
+ setgid(0);
+
+ rtems_current_user_env->euid = rtems_current_user_env->egid = 0;
+
+ fileno(stdout);
+
+ /* fprintf( stderr,
+ "-%s-%s-\n", shell_env->input, shell_env->output );
+ */
+
+ if (shell_env->output && strcmp(shell_env->output, "stdout") != 0) {
+ if (strcmp(shell_env->output, "stderr") == 0) {
+ stdout = stderr;
+ } else if (strcmp(shell_env->output, "/dev/null") == 0) {
+ fclose (stdout);
+ } else {
+ FILE *output = fopen(shell_env_arg->output,
+ shell_env_arg->output_append ? "a" : "w");
+ if (!output) {
+ fprintf(stderr, "shell: open output %s failed: %s\n",
+ shell_env_arg->output, strerror(errno));
+ return false;
+ }
+ stdout = output;
+ stdoutToClose = output;
+ }
+ }
+
+ if (shell_env->input && strcmp(shell_env_arg->input, "stdin") != 0) {
+ FILE *input = fopen(shell_env_arg->input, "r");
+ if (!input) {
+ fprintf(stderr, "shell: open input %s failed: %s\n",
+ shell_env_arg->input, strerror(errno));
+ return false;
+ }
+ stdin = input;
+ stdinToClose = input;
+ shell_env->forever = false;
+ input_file =true;
+ }
+ else {
+ /* make a raw terminal,Linux Manuals */
+ if (tcgetattr(fileno(stdin), &previous_term) >= 0) {
+ term = previous_term;
+ term.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
+ term.c_oflag &= ~OPOST;
+ term.c_oflag |= (OPOST|ONLCR); /* But with cr+nl on output */
+ term.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
+ term.c_cflag |= CLOCAL | CREAD;
+ term.c_cc[VMIN] = 1;
+ term.c_cc[VTIME] = 0;
+ if (tcsetattr (fileno(stdin), TCSADRAIN, &term) < 0) {
+ fprintf(stderr,
+ "shell:cannot set terminal attributes(%s)\n",shell_env->devname);
+ }
+ }
+ cmd_count = RTEMS_SHELL_CMD_COUNT;
+ prompt = malloc(RTEMS_SHELL_PROMPT_SIZE);
+ if (!prompt)
+ fprintf(stderr,
+ "shell:cannot allocate prompt memory\n");
+ }
+
+ setvbuf(stdin,NULL,_IONBF,0); /* Not buffered*/
+ setvbuf(stdout,NULL,_IONBF,0); /* Not buffered*/
+
+ rtems_shell_initialize_command_set();
+
+ /*
+ * Allocate the command line buffers.
+ */
+ cmd_argv = malloc (RTEMS_SHELL_CMD_SIZE);
+ if (!cmd_argv) {
+ fprintf(stderr, "no memory for command line buffers\n" );
+ }
+
+ cmds[0] = calloc (cmd_count, RTEMS_SHELL_CMD_SIZE);
+ if (!cmds[0]) {
+ fprintf(stderr, "no memory for command line buffers\n" );
+ }
+
+ if (cmd_argv && cmds[0]) {
+
+ memset (cmds[0], 0, cmd_count * RTEMS_SHELL_CMD_SIZE);
+
+ for (cmd = 1; cmd < cmd_count; cmd++) {
+ cmds[cmd] = cmds[cmd - 1] + RTEMS_SHELL_CMD_SIZE;
+ }
+
+ do {
+ /* Set again root user and root filesystem, side effect of set_priv..*/
+ sc = rtems_libio_set_private_env();
+ if (sc != RTEMS_SUCCESSFUL) {
+ rtems_error(sc,"rtems_libio_set_private_env():");
+ result = false;
+ break;
+ }
+
+ /*
+ * By using result here, we can fall to the bottom of the
+ * loop when the connection is dropped during login and
+ * keep on trucking.
+ */
+ if (shell_env->login_check != NULL) {
+ result = rtems_shell_login(stdin,stdout);
+ } else {
+ result = true;
+ }
+
+ if (result) {
+ const char *c;
+ memset (cmds[0], 0, cmd_count * RTEMS_SHELL_CMD_SIZE);
+ if (!input_file) {
+ rtems_shell_cat_file(stdout,"/etc/motd");
+ fprintf(stdout, "\n"
+ "RTEMS SHELL (Ver.1.0-FRC):%s. " \
+ __DATE__". 'help' to list commands.\n",
+ shell_env->devname);
+ }
+
+ if (input_file)
+ chdir(shell_env->cwd);
+ else
+ chdir("/"); /* XXX: chdir to getpwent homedir */
+
+ shell_env->exit_shell = false;
+
+ for (;;) {
+ int cmd;
+
+ /* Prompt section */
+ if (prompt) {
+ rtems_shell_get_prompt(shell_env, prompt,
+ RTEMS_SHELL_PROMPT_SIZE);
+ }
+
+ /* getcmd section */
+ cmd = rtems_shell_line_editor(cmds, cmd_count,
+ RTEMS_SHELL_CMD_SIZE, prompt,
+ stdin, stdout);
+
+ if (cmd == -1)
+ continue; /* empty line */
+
+ if (cmd == -2)
+ break; /*EOF*/
+
+ line++;
+
+ if (shell_env->echo)
+ fprintf(stdout, "%d: %s\n", line, cmds[cmd]);
+
+ /* evaluate cmd section */
+ c = cmds[cmd];
+ while (*c) {
+ if (!isblank((unsigned char)*c))
+ break;
+ c++;
+ }
+
+ if (*c == '\0') /* empty line */
+ continue;
+
+ if (*c == '#') { /* comment character */
+ cmds[cmd][0] = 0;
+ continue;
+ }
+
+ if (!strcmp(cmds[cmd],"bye") || !strcmp(cmds[cmd],"exit")) {
+ fprintf(stdout, "Shell exiting\n" );
+ break;
+ } else if (!strcmp(cmds[cmd],"shutdown")) { /* exit application */
+ fprintf(stdout, "System shutting down at user request\n" );
+ exit(0);
+ }
+
+ /* exec cmd section */
+ /* TODO:
+ * To avoid user crash catch the signals.
+ * Open a new stdio files with posibility of redirection *
+ * Run in a new shell task background. (unix &)
+ * Resuming. A little bash.
+ */
+ memcpy (cmd_argv, cmds[cmd], RTEMS_SHELL_CMD_SIZE);
+ if (!rtems_shell_make_args(cmd_argv, &argc, argv,
+ RTEMS_SHELL_MAXIMUM_ARGUMENTS)) {
+ shell_cmd = rtems_shell_lookup_cmd(argv[0]);
+ if ( argv[0] == NULL ) {
+ shell_env->errorlevel = -1;
+ } else if ( shell_cmd == NULL ) {
+ shell_env->errorlevel = rtems_shell_script_file(argc, argv);
+ } else {
+ shell_env->errorlevel = shell_cmd->command(argc, argv);
+ }
+ }
+
+ /* end exec cmd section */
+ if (shell_env->exit_shell)
+ break;
+ }
+
+ fflush( stdout );
+ fflush( stderr );
+ }
+ } while (result && shell_env->forever);
+
+ }
+
+ if (cmds[0])
+ free (cmds[0]);
+ if (cmd_argv)
+ free (cmd_argv);
+ if (prompt)
+ free (prompt);
+
+ if (stdinToClose) {
+ fclose( stdinToClose );
+ } else {
+ if (tcsetattr(fileno(stdin), TCSADRAIN, &previous_term) < 0) {
+ fprintf(
+ stderr,
+ "shell: cannot reset terminal attributes (%s)\n",
+ shell_env->devname
+ );
+ }
+ }
+ if ( stdoutToClose )
+ fclose( stdoutToClose );
+ return result;
+}
+
+/* ----------------------------------------------- */
+static rtems_status_code rtems_shell_run (
+ const char *task_name,
+ size_t task_stacksize,
+ rtems_task_priority task_priority,
+ const char *devname,
+ bool forever,
+ bool wait,
+ const char *input,
+ const char *output,
+ bool output_append,
+ rtems_id wake_on_end,
+ bool echo,
+ rtems_shell_login_check_t login_check
+)
+{
+ rtems_id task_id;
+ rtems_status_code sc;
+ rtems_shell_env_t *shell_env;
+ rtems_name name;
+
+ if ( task_name && strlen(task_name) >= 4)
+ name = rtems_build_name(
+ task_name[0], task_name[1], task_name[2], task_name[3]);
+ else
+ name = rtems_build_name( 'S', 'E', 'N', 'V' );
+
+ sc = rtems_task_create(
+ name,
+ task_priority,
+ task_stacksize,
+ RTEMS_PREEMPT | RTEMS_TIMESLICE | RTEMS_NO_ASR,
+ RTEMS_LOCAL | RTEMS_FLOATING_POINT,
+ &task_id
+ );
+ if (sc != RTEMS_SUCCESSFUL) {
+ rtems_error(sc,"creating task %s in shell_init()",task_name);
+ return sc;
+ }
+
+ shell_env = rtems_shell_init_env( NULL );
+ if ( !shell_env ) {
+ rtems_error(RTEMS_NO_MEMORY,
+ "allocating shell_env %s in shell_init()",task_name);
+ return RTEMS_NO_MEMORY;
+ }
+ shell_env->devname = devname;
+ shell_env->taskname = task_name;
+ shell_env->exit_shell = false;
+ shell_env->forever = forever;
+ shell_env->echo = echo;
+ shell_env->input = strdup (input);
+ shell_env->output = strdup (output);
+ shell_env->output_append = output_append;
+ shell_env->wake_on_end = wake_on_end;
+ shell_env->login_check = login_check;
+
+ getcwd(shell_env->cwd, sizeof(shell_env->cwd));
+
+ sc = rtems_task_start(task_id, rtems_shell_task,
+ (rtems_task_argument) shell_env);
+ if (sc != RTEMS_SUCCESSFUL) {
+ rtems_error(sc,"starting task %s in shell_init()",task_name);
+ return sc;
+ }
+
+ if (wait) {
+ rtems_event_set out;
+ sc = rtems_event_receive (RTEMS_EVENT_1, RTEMS_WAIT, 0, &out);
+ }
+
+ return 0;
+}
+
+rtems_status_code rtems_shell_init(
+ const char *task_name,
+ size_t task_stacksize,
+ rtems_task_priority task_priority,
+ const char *devname,
+ bool forever,
+ bool wait,
+ rtems_shell_login_check_t login_check
+)
+{
+ rtems_id to_wake = RTEMS_ID_NONE;
+
+ if ( wait )
+ to_wake = rtems_task_self();
+
+ return rtems_shell_run(
+ task_name, /* task_name */
+ task_stacksize, /* task_stacksize */
+ task_priority, /* task_priority */
+ devname, /* devname */
+ forever, /* forever */
+ wait, /* wait */
+ "stdin", /* input */
+ "stdout", /* output */
+ false, /* output_append */
+ to_wake, /* wake_on_end */
+ false, /* echo */
+ login_check /* login check */
+ );
+}
+
+rtems_status_code rtems_shell_script (
+ const char *task_name,
+ size_t task_stacksize,
+ rtems_task_priority task_priority,
+ const char* input,
+ const char* output,
+ bool output_append,
+ bool wait,
+ bool echo
+)
+{
+ rtems_id current_task = RTEMS_INVALID_ID;
+ rtems_status_code sc;
+
+ if (wait) {
+ sc = rtems_task_ident (RTEMS_SELF, RTEMS_LOCAL, &current_task);
+ if (sc != RTEMS_SUCCESSFUL)
+ return sc;
+ }
+
+ sc = rtems_shell_run(
+ task_name, /* task_name */
+ task_stacksize, /* task_stacksize */
+ task_priority, /* task_priority */
+ NULL, /* devname */
+ 0, /* forever */
+ wait, /* wait */
+ input, /* input */
+ output, /* output */
+ output_append, /* output_append */
+ current_task, /* wake_on_end */
+ echo, /* echo */
+ NULL /* login check */
+ );
+ if (sc != RTEMS_SUCCESSFUL)
+ return sc;
+
+ return sc;
+}