From d007cc2ceef48ce47c157512370c1bf2c45596f3 Mon Sep 17 00:00:00 2001 From: Chris Johns Date: Tue, 14 Apr 2020 15:26:27 +1000 Subject: libmisc/shell: Fix the handling of joel scripts in telnet - Fix the passing of std[in/out] to child threads - Fix deleting of managed memory in the key destructor - Only set the key in the main loop thread - Only allocate a shell env outside of the main loop - Fix memory leak if the task start fails - Remove error level from shell env, it cannot be returned this way. Add exit_code but the API is broken so it cannot be returned. Closes #3859 --- cpukit/include/rtems/shell.h | 7 +- cpukit/libmisc/shell/shell.c | 369 +++++++++++++++++++++++++++---------- testsuites/libtests/shell01/init.c | 123 ++++++++++++- 3 files changed, 394 insertions(+), 105 deletions(-) diff --git a/cpukit/include/rtems/shell.h b/cpukit/include/rtems/shell.h index 973db16605..d705dcb0a7 100644 --- a/cpukit/include/rtems/shell.h +++ b/cpukit/include/rtems/shell.h @@ -220,16 +220,21 @@ extern rtems_status_code rtems_shell_script( typedef struct { /** 'S','E','N','V': Shell Environment */ rtems_name magic; + bool managed; const char *devname; const char *taskname; bool exit_shell; /* logout */ bool forever; /* repeat login */ - int errorlevel; + int *exit_code; + bool exit_on_error; bool echo; char cwd[256]; const char *input; const char *output; bool output_append; + FILE *parent_stdin; + FILE *parent_stdout; + FILE *parent_stderr; rtems_id wake_on_end; rtems_shell_login_check_t login_check; diff --git a/cpukit/libmisc/shell/shell.c b/cpukit/libmisc/shell/shell.c index c2ea3c4afa..f00ae54b49 100644 --- a/cpukit/libmisc/shell/shell.c +++ b/cpukit/libmisc/shell/shell.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -38,22 +39,44 @@ #include #include +#define SHELL_STD_DEBUG 0 + +#if SHELL_STD_DEBUG +#include +#define shell_std_debug(...) \ + do { printk("shell[%08x]: ", rtems_task_self()); printk(__VA_ARGS__); } while (0) +#else +#define shell_std_debug(...) +#endif + const rtems_shell_env_t rtems_global_shell_env = { .magic = rtems_build_name('S', 'E', 'N', 'V'), + .managed = false, .devname = CONSOLE_DEVICE_NAME, .taskname = "SHGL", .exit_shell = false, .forever = true, - .errorlevel = -1, .echo = false, .cwd = "/", .input = NULL, .output = NULL, .output_append = false, + .parent_stdin = NULL, + .parent_stdout = NULL, + .parent_stderr = NULL, .wake_on_end = RTEMS_ID_NONE, - .login_check = NULL + .exit_code = NULL, + .login_check = NULL, + .uid = 0, + .gid = 0 }; +typedef struct rtems_shell_env_key_handle +{ + bool managed; + rtems_shell_env_t* env; +} rtems_shell_env_key_handle; + static pthread_once_t rtems_shell_once = PTHREAD_ONCE_INIT; static pthread_key_t rtems_shell_current_env_key; @@ -62,7 +85,7 @@ static pthread_key_t rtems_shell_current_env_key; * Initialize the shell user/process environment information */ static rtems_shell_env_t *rtems_shell_init_env( - rtems_shell_env_t *shell_env_p + rtems_shell_env_t *shell_env_parent ) { rtems_shell_env_t *shell_env; @@ -70,12 +93,17 @@ static rtems_shell_env_t *rtems_shell_init_env( shell_env = malloc(sizeof(rtems_shell_env_t)); if ( !shell_env ) return NULL; - if ( !shell_env_p ) { + + if ( shell_env_parent == NULL ) { + shell_env_parent = rtems_shell_get_current_env(); + } + if ( shell_env_parent == NULL ) { *shell_env = rtems_global_shell_env; - shell_env->taskname = NULL; } else { - *shell_env = *shell_env_p; + *shell_env = *shell_env_parent; } + shell_env->managed = true; + shell_env->taskname = NULL; return shell_env; } @@ -87,17 +115,20 @@ static void rtems_shell_env_free( void *ptr ) { - rtems_shell_env_t *shell_env; - shell_env = (rtems_shell_env_t *) ptr; - - if ( !ptr ) - return; + if ( ptr != NULL ) { + rtems_shell_env_key_handle *handle = (rtems_shell_env_key_handle *) ptr; + rtems_shell_env_t *shell_env = handle->env; + + if ( handle->managed ) { + if ( shell_env->input ) + free((void *)shell_env->input); + if ( shell_env->output ) + free((void *)shell_env->output); + free( shell_env ); + } - if ( shell_env->input ) - free((void *)shell_env->input); - if ( shell_env->output ) - free((void *)shell_env->output); - free( ptr ); + free( handle ); + } } static void rtems_shell_create_file(const char *name, const char *content) @@ -153,12 +184,73 @@ void rtems_shell_init_environment(void) assert(pthread_once(&rtems_shell_once, rtems_shell_init_once) == 0); } +/* + * Set the shell env into the current thread's shell key. + */ +static bool rtems_shell_set_shell_env( + rtems_shell_env_t* shell_env +) +{ + /* + * The shell environment can be managed or it can be provided by a + * user. We need to create a handle to hold the env pointer. + */ + rtems_shell_env_key_handle *handle; + int eno; + + handle = malloc(sizeof(rtems_shell_env_key_handle)); + if (handle == NULL) { + rtems_error(0, "no memory for shell env key handle)"); + return false; + } + + handle->managed = shell_env->managed; + handle->env = shell_env; + + eno = pthread_setspecific(rtems_shell_current_env_key, handle); + if (eno != 0) { + rtems_error(0, "pthread_setspecific(shell_current_env_key): set"); + return false; + } + + return true; +} + +/* + * Clear the current thread's shell key. + */ +static void rtems_shell_clear_shell_env(void) +{ + int eno; + + /* + * Run the destructor manually. + */ + rtems_shell_env_free(pthread_getspecific(rtems_shell_current_env_key)); + + /* + * Clear the key + */ + eno = pthread_setspecific(rtems_shell_current_env_key, NULL); + if (eno != 0) + rtems_error(0, "pthread_setspecific(shell_current_env_key): clear"); + + /* + * Clear stdin and stdout file pointers of they will be closed + */ + stdin = NULL; + stdout = NULL; +} + /* * Return the current shell environment */ rtems_shell_env_t *rtems_shell_get_current_env(void) { - return (rtems_shell_env_t *) pthread_getspecific(rtems_shell_current_env_key); + rtems_shell_env_key_handle *handle; + handle = (rtems_shell_env_key_handle*) + pthread_getspecific(rtems_shell_current_env_key); + return handle == NULL ? NULL : handle->env; } /* @@ -168,15 +260,27 @@ rtems_shell_env_t *rtems_shell_get_current_env(void) void rtems_shell_dup_current_env(rtems_shell_env_t *copy) { rtems_shell_env_t *env = rtems_shell_get_current_env(); - if (env) { + if (env != NULL) { + shell_std_debug("dup: existing parent\n"); *copy = *env; } else { - memset(copy, 0, sizeof(rtems_shell_env_t)); - copy->magic = rtems_build_name('S', 'E', 'N', 'V'); - copy->devname = CONSOLE_DEVICE_NAME; - copy->taskname = "RTSH"; + *copy = rtems_global_shell_env; + copy->magic = rtems_build_name('S', 'E', 'N', 'V'); + copy->devname = CONSOLE_DEVICE_NAME; + copy->taskname = "RTSH"; + copy->parent_stdout = stdout; + copy->parent_stdin = stdin; + copy->parent_stderr = stderr; + shell_std_debug("dup: global: copy: %p out: %d (%p) in: %d (%p)\n", + copy, + fileno(copy->parent_stdout), copy->parent_stdout, + fileno(copy->parent_stdin), copy->parent_stdin); } + /* + * Duplicated environments are not managed. + */ + copy->managed = false; } /* @@ -201,14 +305,21 @@ static int rtems_shell_line_editor( int up; int cmd = -1; int inserting = 1; + int in_fileno = fileno(in); + int out_fileno = fileno(out); - output = (out && isatty(fileno(in))); + /* + * Only this task can use this file descriptor because calling + * fileno will block if another thread call made a call on this + * descriptor. + */ + output = (out && isatty(in_fileno)); col = last_col = 0; - tcdrain(fileno(in)); + tcdrain(in_fileno); if (out) - tcdrain(fileno(out)); + tcdrain(out_fileno); if (output && prompt) fprintf(out, "\r%s", prompt); @@ -544,9 +655,9 @@ static int rtems_shell_line_editor( static bool rtems_shell_login(rtems_shell_env_t *env, FILE * in,FILE * out) { - FILE *fd; - int c; - time_t t; + FILE *fd; + int c; + time_t t; if (out) { if ((env->devname[5]!='p')|| @@ -554,9 +665,9 @@ static bool rtems_shell_login(rtems_shell_env_t *env, FILE * in,FILE * out) (env->devname[7]!='y')) { fd = fopen("/etc/issue","r"); if (fd) { - while ((c=fgetc(fd))!=EOF) { + while ((c = fgetc(fd)) != EOF) { if (c=='@') { - switch(c=fgetc(fd)) { + switch (c = fgetc(fd)) { case 'L': fprintf(out,"%s", env->devname); break; @@ -688,6 +799,7 @@ static bool rtems_shell_init_user_env(void) /* Make sure we have a private user environment */ sc = rtems_libio_set_private_env(); if (sc != RTEMS_SUCCESSFUL) { + rtems_error(sc, "rtems_libio_set_private_env():"); return false; } @@ -704,103 +816,115 @@ static bool rtems_shell_init_user_env(void) #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_env_t *shell_env; - int eno; - 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; + 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_init_environment(); - shell_env = rtems_shell_init_env(shell_env_arg); - if (shell_env == NULL) { + if (shell_env->magic != rtems_build_name('S', 'E', 'N', 'V')) { + rtems_error(0, "invalid shell environment passed to the main loop)"); return false; } - eno = pthread_setspecific(rtems_shell_current_env_key, shell_env); - if (eno != 0) { + if (!rtems_shell_set_shell_env(shell_env)) return false; - } if (!rtems_shell_init_user_env()) { + rtems_error(0, "rtems_shell_init_user_env"); + rtems_shell_clear_shell_env(); return false; } - fileno(stdout); - - /* fprintf( stderr, - "-%s-%s-\n", shell_env->input, shell_env->output ); - */ + shell_std_debug("env: %p\n", shell_env); - if (shell_env->output && strcmp(shell_env->output, "stdout") != 0) { - if (strcmp(shell_env->output, "stderr") == 0) { + if (shell_env->output == NULL || strcmp(shell_env->output, "stdout") == 0) { + if (shell_env->parent_stdout != NULL) + stdout = shell_env->parent_stdout; + } + else if (strcmp(shell_env->output, "stderr") == 0) { + if (shell_env->parent_stderr != NULL) + stdout = shell_env->parent_stderr; + else 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; + } else if (strcmp(shell_env->output, "/dev/null") == 0) { + fclose (stdout); + } else { + FILE *output = fopen(shell_env->output, + shell_env->output_append ? "a" : "w"); + if (output == NULL) { + fprintf(stderr, "shell: open output %s failed: %s\n", + shell_env->output, strerror(errno)); + rtems_shell_clear_shell_env(); + 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) { + if (shell_env->input == NULL || strcmp(shell_env->input, "stdin") == 0) { + if (shell_env->parent_stdin != NULL) + stdin = shell_env->parent_stdin; + } else { + FILE *input = fopen(shell_env->input, "r"); + if (input == NULL) { fprintf(stderr, "shell: open input %s failed: %s\n", - shell_env_arg->input, strerror(errno)); + shell_env->input, strerror(errno)); + if (stdoutToClose != NULL) + fclose(stdoutToClose); + rtems_shell_clear_shell_env(); return false; } stdin = input; stdinToClose = input; shell_env->forever = false; - input_file =true; + input_file = true; } - else { - /* make a raw terminal,Linux Manuals */ + + if (!input_file) { + /* 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_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); + "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"); + "shell: cannot allocate prompt memory\n"); } - setvbuf(stdin,NULL,_IONBF,0); /* Not buffered*/ - setvbuf(stdout,NULL,_IONBF,0); /* Not buffered*/ + shell_std_debug("child out: %d (%p)\n", fileno(stdout), stdout); + shell_std_debug("child in: %d (%p)\n", fileno(stdin), stdin); + + /* Do not buffer if interactive else leave buffered */ + if (!input_file) + setvbuf(stdin, NULL, _IONBF, 0); + setvbuf(stdout, NULL, _IONBF, 0); /* * Allocate the command line buffers. @@ -863,8 +987,6 @@ bool rtems_shell_main_loop( shell_env->exit_shell = false; for (;;) { - int cmd; - /* Prompt section */ if (prompt) { rtems_shell_get_prompt(shell_env, prompt, @@ -879,8 +1001,10 @@ bool rtems_shell_main_loop( if (cmd == -1) continue; /* empty line */ - if (cmd == -2) + if (cmd == -2) { + result = false; break; /*EOF*/ + } line++; @@ -918,7 +1042,11 @@ bool rtems_shell_main_loop( memcpy (cmd_argv, cmds[cmd], RTEMS_SHELL_CMD_SIZE); if (!rtems_shell_make_args(cmd_argv, &argc, argv, RTEMS_SHELL_MAXIMUM_ARGUMENTS)) { - shell_env->errorlevel = rtems_shell_execute_cmd(argv[0], argc, argv); + int exit_code = rtems_shell_execute_cmd(argv[0], argc, argv); + if (shell_env->exit_code != NULL) + *shell_env->exit_code = exit_code; + if (exit_code != 0 && shell_env->exit_on_error) + shell_env->exit_shell = true; } /* end exec cmd section */ @@ -929,6 +1057,7 @@ bool rtems_shell_main_loop( fflush( stdout ); fflush( stderr ); } + shell_std_debug("end: %d %d\n", result, shell_env->forever); } while (result && shell_env->forever); } @@ -940,6 +1069,9 @@ bool rtems_shell_main_loop( if (prompt) free (prompt); + shell_std_debug("child in-to-close: %p\n", stdinToClose); + shell_std_debug("child out-to-close: %p\n", stdoutToClose); + if (stdinToClose) { fclose( stdinToClose ); } else { @@ -953,6 +1085,7 @@ bool rtems_shell_main_loop( } if ( stdoutToClose ) fclose( stdoutToClose ); + rtems_shell_clear_shell_env(); return result; } @@ -968,6 +1101,7 @@ static rtems_status_code rtems_shell_run ( const char *output, bool output_append, rtems_id wake_on_end, + int *exit_code, bool echo, rtems_shell_login_check_t login_check ) @@ -977,6 +1111,8 @@ static rtems_status_code rtems_shell_run ( rtems_shell_env_t *shell_env; rtems_name name; + rtems_shell_init_environment(); + if ( task_name && strlen(task_name) >= 4) name = rtems_build_name( task_name[0], task_name[1], task_name[2], task_name[3]); @@ -992,31 +1128,51 @@ static rtems_status_code rtems_shell_run ( &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_std_debug("run: env: %p\n", shell_env); + 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->input = input == NULL ? NULL : strdup (input); + shell_env->output = output == NULL ? NULL : strdup (output); shell_env->output_append = output_append; + shell_env->parent_stdin = stdin; + shell_env->parent_stdout = stdout; + shell_env->parent_stderr = stderr; shell_env->wake_on_end = wake_on_end; + shell_env->exit_code = exit_code; shell_env->login_check = login_check; shell_env->uid = getuid(); shell_env->gid = getgid(); getcwd(shell_env->cwd, sizeof(shell_env->cwd)); + shell_std_debug("run out: %d (%p)\n", + fileno(shell_env->parent_stdout), shell_env->parent_stdout); + shell_std_debug("run in: %d (%p)\n", + fileno(shell_env->parent_stdin), shell_env->parent_stdin); + sc = rtems_task_start(task_id, rtems_shell_task, - (rtems_task_argument) shell_env); + (rtems_task_argument) shell_env); if (sc != RTEMS_SUCCESSFUL) { + rtems_error(sc,"starting task %s in shell_init()",task_name); + free( (void*) shell_env->input ); + free( (void*) shell_env->output ); + free( shell_env ); return sc; } @@ -1025,7 +1181,9 @@ static rtems_status_code rtems_shell_run ( sc = rtems_event_receive (RTEMS_EVENT_1, RTEMS_WAIT, 0, &out); } - return 0; + shell_std_debug("run: end: sc:%d ec:%d\n", sc, *exit_code); + + return sc; } rtems_status_code rtems_shell_init( @@ -1039,6 +1197,7 @@ rtems_status_code rtems_shell_init( ) { rtems_id to_wake = RTEMS_ID_NONE; + int exit_code = 0; if ( wait ) to_wake = rtems_task_self(); @@ -1054,12 +1213,13 @@ rtems_status_code rtems_shell_init( "stdout", /* output */ false, /* output_append */ to_wake, /* wake_on_end */ + &exit_code, /* exit code of command */ false, /* echo */ login_check /* login check */ ); } -rtems_status_code rtems_shell_script ( +rtems_status_code rtems_shell_script ( const char *task_name, size_t task_stacksize, rtems_task_priority task_priority, @@ -1070,14 +1230,14 @@ rtems_status_code rtems_shell_script ( bool echo ) { - rtems_id current_task = RTEMS_INVALID_ID; + rtems_id to_wake = RTEMS_ID_NONE; + int exit_code = 0; rtems_status_code sc; - if (wait) { - sc = rtems_task_ident (RTEMS_SELF, RTEMS_LOCAL, ¤t_task); - if (sc != RTEMS_SUCCESSFUL) - return sc; - } + shell_std_debug("script: in: %s out: %s\n", input, output); + + if ( wait ) + to_wake = rtems_task_self(); sc = rtems_shell_run( task_name, /* task_name */ @@ -1089,12 +1249,19 @@ rtems_status_code rtems_shell_script ( input, /* input */ output, /* output */ output_append, /* output_append */ - current_task, /* wake_on_end */ + to_wake, /* wake_on_end */ + &exit_code, /* exit_code */ echo, /* echo */ NULL /* login check */ ); - if (sc != RTEMS_SUCCESSFUL) - return sc; + + if (sc == RTEMS_SUCCESSFUL) + { + /* Place holder until RTEMS 5 is released then the interface for + * this call will change. */ + } + + shell_std_debug("script: end: %d\n", sc); return sc; } diff --git a/testsuites/libtests/shell01/init.c b/testsuites/libtests/shell01/init.c index 545d695d86..5085c3c803 100644 --- a/testsuites/libtests/shell01/init.c +++ b/testsuites/libtests/shell01/init.c @@ -50,6 +50,122 @@ static const char etc_group[] = "E::7:y,z\n" "F::8:s,moop,t\n"; +static const char joel_in[] = + "#! joel\n" + "jtst hello world\n" + "jtst 1 2 3 4 5\n"; + +static const char joel_out_1[] = + " 3 'jtst hello world'\n" + " 6 'jtst 1 2 3 4 5'\n"; + +static const char joel_out_2[] = + "\n" + "RTEMS Shell on (null). Use 'help' to list commands.\n" + " 3 'jtst hello world'\n" + " 6 'jtst 1 2 3 4 5'\n"; + +static int joel_test_command(int argc, char** argv) +{ + int i; + fprintf(stdout, "%2d '", argc); + for (i = 0; i < argc; ++i) { + fprintf(stdout, argv[i]); + if (i < (argc - 1)) + fprintf(stdout, " "); + } + fprintf(stdout, "'\n"); + return 0; +} + +static void test_joel(void) +{ + /* + * Running a joel script tests the shell main loop. + */ + char buf[sizeof(joel_out_2) + 1]; + rtems_shell_cmd_t* cmd; + FILE *in; + FILE *out; + FILE *current_stdout = stdout; + FILE *current_stdin = stdin; + size_t len; + rtems_status_code sc; + + /* + * Use a private command due to the way the testsuite maps printk onto printf. + */ + cmd = rtems_shell_add_cmd("jtst", "misc", "joel test", joel_test_command); + rtems_test_assert(cmd != NULL); + + len = strlen(joel_in); + + in = fopen("/jin", "w"); + rtems_test_assert(in != NULL); + rtems_test_assert(fwrite(joel_in, sizeof(char), len, in) == len); + rtems_test_assert(fclose(in) == 0); + + /* + * The shell opens the input and output files. + */ + sc = rtems_shell_script( + "JTST", + 8 * 1024, + 1, + "/jin", + "/jout", + false, + true, + false); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + out = fopen("/jout", "r"); + rtems_test_assert(out != NULL); + rtems_test_assert(!feof(out)); + memset(buf, 0, sizeof(buf)); + len = fread(buf, sizeof(char), sizeof(buf), out); + rtems_test_assert(len > 0); + rtems_test_assert(strcmp(joel_out_1, buf) == 0); + rtems_test_assert(fclose(out) == 0); + + /* + * The shell task inherits the parent stdin and stdout + */ + in = fopen("/jin", "r"); + rtems_test_assert(in != NULL); + out = fopen("/jout", "w"); + rtems_test_assert(out != NULL); + + stdin = in; + stdout = out; + + sc = rtems_shell_script( + "JTST", + 8 * 1024, + 1, + "stdin", + "stdout", + false, + true, + false); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + + stdout = current_stdout; + stdin = current_stdin; + + rtems_test_assert(fclose(in) == 0); + rtems_test_assert(fclose(out) == 0); + + out = fopen("/jout", "r"); + rtems_test_assert(out != NULL); + rtems_test_assert(!feof(out)); + memset(buf, 0, sizeof(buf)); + len = fread(buf, sizeof(char), sizeof(buf), out); + rtems_test_assert(len > 0); + rtems_test_assert(strcmp(joel_out_2, buf) == 0); + rtems_test_assert(fclose(out) == 0); +} + static void test(void) { rtems_user_env_t *uenv; @@ -163,6 +279,7 @@ static void Init(rtems_task_argument arg) TEST_BEGIN(); test(); + test_joel(); TEST_END(); rtems_test_exit(0); @@ -171,10 +288,10 @@ static void Init(rtems_task_argument arg) #define CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER #define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER -#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 4 +#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 5 -#define CONFIGURE_MAXIMUM_TASKS 1 -#define CONFIGURE_MAXIMUM_POSIX_KEYS 1 +#define CONFIGURE_MAXIMUM_TASKS 3 +#define CONFIGURE_MAXIMUM_POSIX_KEYS 2 #define CONFIGURE_MAXIMUM_POSIX_KEY_VALUE_PAIRS 2 #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION -- cgit v1.2.3