/* * 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 __attribute__((unused)), 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: command not found\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 the first 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; }
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; }
/* * DESCRIPTION: Init task for any Microwindows/RTEMS application. */ void *POSIX_Init( void *argument ) { #define ARGV_LIMIT 32 #define LINE_LIMIT 128 int sc; int mainArgc; char *mainArgv[ARGV_LIMIT]; char Line[LINE_LIMIT]; DPRINTF( "\nStarting RTEMS init task...\n" ); DPRINTF( "" ); DPRINTF("Loading filesystem image\n"); (void) Untar_FromMemory( (char *)FilesystemImage, FilesystemImage_size ); #if !defined(NONETWORK) /* Make all network initialization */ rtems_bsdnet_initialize_network(); DPRINTF( "Network Initialization is complete.\n\n" ); #endif setenv( "HOME", "/", 1 ); setenv( "T1LIB_CONFIG", "/fonts/t1lib/t1lib.config", 1 ); /* * Clear argv pointer array */ for ( mainArgc=0 ; mainArgc<ARGV_LIMIT ; mainArgc++ ) mainArgv[mainArgc] = NULL; strcpy( Line, "RTEMS " ); #if 0 /* defined(WITH_ARGS) */ DPRINTF("With arguments\n" ); { char *p; DPRINTF("Enter arguments> " ); p = fgets( &Line[6], LINE_LIMIT - 6, stdin ); if ( !p ) { DPRINTF("error reading arguments\n" ); exit(0); } } #else DPRINTF("Without arguments\n" ); #endif /* * Break into arguments */ sc = rtems_shell_make_args( Line, &mainArgc, mainArgv, ARGV_LIMIT - 1 ); if ( sc ) { DPRINTF("Error parsing arguments\n" ); exit(0); } rtems_main( mainArgc, mainArgv ); DPRINTF( "*** Done ***\n\n\n" ); pthread_exit( NULL ); return NULL; /* just so the compiler thinks we returned something */ }