/*
 *  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;
}
Ejemplo n.º 2
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;
}
Ejemplo n.º 3
0
/*
 * 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 */
}