Пример #1
0
rtems_task Init(
  rtems_task_argument argument
)
{
  puts( "\n\n*** TEST Tests for error reporting routines - 01 ***" );

  errno = -1;
  rtems_error(RTEMS_ERROR_ERRNO, "Dummy: Resources unavailable");

  errno = ENOMEM;
  rtems_error(
    RTEMS_NO_MEMORY | RTEMS_ERROR_ERRNO,
    "Dummy: Resources unavailable"
  );

  puts( "Dummy: causing panic.. will print test end message, then..." );
  puts( "       print various error messages" );
  rtems_error(
    RTEMS_NO_MEMORY | RTEMS_ERROR_PANIC,
    "Dummy: Resources unavailable\n"
    "*** END OF TEST Tests for error reporting routines - 01 ***\n"
  );
  
  rtems_test_exit(0);
}
rtems_id
telnetd_dflt_spawn(const char *name, unsigned int priority, unsigned int stackSize, void (*fn)(void *), void* fnarg)
{
  rtems_status_code        sc;
  rtems_id                 task_id = RTEMS_ID_NONE;
  char                     nm[4] = {'X','X','X','X' };
  struct wrap_delete_args *pwa = malloc(sizeof(*pwa));

  strncpy(nm, name, 4);

  if ( !pwa ) {
    perror("Telnetd: no memory\n");
    return RTEMS_ID_NONE;
  }

  pwa->t = fn;
  pwa->a = fnarg;

  if ((sc=rtems_task_create(
    rtems_build_name(nm[0], nm[1], nm[2], nm[3]),
      (rtems_task_priority)priority,
      stackSize,
      RTEMS_DEFAULT_MODES,
      RTEMS_DEFAULT_ATTRIBUTES | RTEMS_FLOATING_POINT,
      &task_id)) ||
    (sc=rtems_task_start(
      task_id,
      wrap_delete,
      (rtems_task_argument)pwa))) {
        free(pwa);
        rtems_error(sc,"Telnetd: spawning task failed");
        return RTEMS_ID_NONE;
  }
  return task_id;
}
Пример #3
0
void
rtems_monitor_init(
    uint32_t   monitor_flags
)
{
    rtems_status_code status;

    rtems_monitor_kill();

    status = rtems_task_create(RTEMS_MONITOR_NAME,
                               1,
                               RTEMS_MINIMUM_STACK_SIZE * 2,
                               RTEMS_INTERRUPT_LEVEL(0),
                               RTEMS_DEFAULT_ATTRIBUTES,
                               &rtems_monitor_task_id);
    if (status != RTEMS_SUCCESSFUL)
    {
        rtems_error(status, "could not create monitor task");
        return;
    }

    rtems_monitor_node = rtems_object_id_get_node(rtems_monitor_task_id);
    rtems_monitor_default_node = rtems_monitor_node;

    rtems_monitor_server_init(monitor_flags);

    if (!(monitor_flags & RTEMS_MONITOR_NOTASK)) {
      /*
       * Start the monitor task itself
       */
      status = rtems_task_start(
        rtems_monitor_task_id, rtems_monitor_task, monitor_flags);
      if (status != RTEMS_SUCCESSFUL) {
        rtems_error(status, "could not start monitor");
        return;
      }
   }
}
Пример #4
0
void rtems_panic(
  const char *printf_format,
  ...
)
{
  va_list arglist;

  va_start(arglist, printf_format);
  (void) rtems_verror(RTEMS_ERROR_PANIC, printf_format, arglist);
  va_end(arglist);

  rtems_error(0, "fatal error, exiting");
  _exit(errno);
}
Пример #5
0
rtems_task Init(
  rtems_task_argument argument
)
{
  TEST_BEGIN();

  errno = -1;
  rtems_error(RTEMS_ERROR_ERRNO, "Dummy: Resources unavailable");

  errno = ENOMEM;
  rtems_error(
    RTEMS_NO_MEMORY | RTEMS_ERROR_ERRNO,
    "Dummy: Resources unavailable"
  );

  puts( "Dummy: causing panic.. will print test end message, then..." );
  puts( "       print various error messages" );
  rtems_error(
    RTEMS_NO_MEMORY | RTEMS_ERROR_PANIC,
    "Dummy: Resources unavailable\n"
  );

  rtems_test_assert(0);
}
Пример #6
0
int rtems_error(
  rtems_error_code_t error_flag,
  const char *printf_format,
  ...
)
{
  va_list arglist;
  int chars_written;

  va_start(arglist, printf_format);
  chars_written = rtems_verror(error_flag, printf_format, arglist);
  va_end(arglist);

  if (error_flag & RTEMS_ERROR_PANIC) {
    rtems_error(0, "fatal error, exiting");
    _exit(errno);
  }
  if (error_flag & RTEMS_ERROR_ABORT) {
    rtems_error(0, "fatal error, aborting");
    abort();
  }

  return chars_written;
}
Пример #7
0
rtems_task Init(
  rtems_task_argument argument
)
{
  puts( "\n\n*** TEST Tests for error reporting routines - 02 ***" );

  errno = ENOMEM;
  rtems_error(
    RTEMS_NO_MEMORY | RTEMS_ERROR_ABORT, 
    "Dummy: Resources unavailable\n"
    "*** END OF TEST Tests for error reporting routines - 02 ***\n"
  );
  

  rtems_test_exit(0);
}
Пример #8
0
/* ----------------------------------------------- */
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;
}
Пример #9
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;
}
Пример #10
0
rtems_status_code
rtems_monitor_server_request(
    uint32_t                         server_node,
    rtems_monitor_server_request_t  *request,
    rtems_monitor_server_response_t *response
)
{
    rtems_id          server_id;
    rtems_status_code status;
    size_t            size;

    /*
     * What is id of monitor on target node?
     * Look it up if we don't know it yet.
     */

    server_id = rtems_monitor_server_request_queue_ids[server_node];
    if (server_id == 0)
    {
        status = rtems_message_queue_ident(RTEMS_MONITOR_QUEUE_NAME,
                                           server_node,
                                           &server_id);
        if (status != RTEMS_SUCCESSFUL)
        {
            rtems_error(status, "ident of remote server failed");
            goto done;
        }

        rtems_monitor_server_request_queue_ids[server_node] = server_id;
    }

    request->return_id = rtems_monitor_server_response_queue_id;

    status = rtems_message_queue_send(server_id, request, sizeof(*request));
    if (status != RTEMS_SUCCESSFUL)
    {
        rtems_error(status, "monitor server request send failed");
        goto done;
    }

    /*
     * Await response, if requested
     */

    if (response)
    {
        status = rtems_message_queue_receive(rtems_monitor_server_response_queue_id,
                                             response,
                                             &size,
                                             RTEMS_WAIT,
                                             100);
        if (status != RTEMS_SUCCESSFUL)
        {
            rtems_error(status, "server did not respond");

            /* maybe server task was restarted; look it up again next time */
            rtems_monitor_server_request_queue_ids[server_node] = 0;

            goto done;
        }

        if (response->command != RTEMS_MONITOR_SERVER_RESPONSE)
        {
            status = RTEMS_INCORRECT_STATE;
            goto done;
        }
    }

done:
    return status;
}
Пример #11
0
void
rtems_monitor_server_init(
    uint32_t   monitor_flags __attribute__((unused))
)
{
    #if defined(RTEMS_MULTIPROCESSING)
    rtems_status_code status;

    if (_System_state_Is_multiprocessing    &&
        (_Configuration_MP_table->maximum_nodes > 1))
    {
        uint32_t   maximum_nodes = _Configuration_MP_table->maximum_nodes;

        /*
         * create the msg que our server will listen
         * Since we only get msgs from other RTEMS monitors, we just
         * need reserve space for 1 msg from each node.
         */

        status = rtems_message_queue_create(
                       RTEMS_MONITOR_QUEUE_NAME,
                       maximum_nodes,
                       sizeof(rtems_monitor_server_request_t),
                       RTEMS_GLOBAL,
                       &rtems_monitor_server_request_queue_id);

        if (status != RTEMS_SUCCESSFUL)
        {
            rtems_error(status, "could not create monitor server message queue");
            goto done;
        }

        /*
         * create the msg que our responses will come on
         * Since monitor just does one thing at a time, we only need 1 item
         * message queue.
         */

        status = rtems_message_queue_create(
                       RTEMS_MONITOR_RESPONSE_QUEUE_NAME,
                       1, /* depth */
                       sizeof(rtems_monitor_server_response_t),
                       RTEMS_GLOBAL,
                       &rtems_monitor_server_response_queue_id);

        if (status != RTEMS_SUCCESSFUL)
        {
            rtems_error(status, "could not create monitor response message queue");
            goto done;
        }

        /* need an id for queue of each other server we might talk to */
        /* indexed by node, so add 1 to maximum_nodes */
        rtems_monitor_server_request_queue_ids =
                   (rtems_id *) malloc((maximum_nodes + 1) * sizeof(rtems_id));
        (void) memset(rtems_monitor_server_request_queue_ids,
                      0,
                      (maximum_nodes + 1) * sizeof(rtems_id));

        rtems_monitor_server_request_queue_ids[rtems_monitor_node] =
                   rtems_monitor_server_request_queue_id;

        /*
         * create the server task
         */
        status = rtems_task_create(RTEMS_MONITOR_SERVER_NAME,
                                   1,
                                   0 /* default stack */,
                                   RTEMS_INTERRUPT_LEVEL(0),
                                   RTEMS_DEFAULT_ATTRIBUTES,
                                   &rtems_monitor_server_task_id);
        if (status != RTEMS_SUCCESSFUL)
        {
            rtems_error(status, "could not create monitor server task");
            goto done;
        }

        /*
         * Start the server task
         */
        status = rtems_task_start(rtems_monitor_server_task_id,
                                  rtems_monitor_server_task,
                                  monitor_flags);
        if (status != RTEMS_SUCCESSFUL)
        {
            rtems_error(status, "could not start monitor server");
            goto done;
        }
    }

done:
    #endif
    return;
}
Пример #12
0
void
rtems_monitor_server_task(
    rtems_task_argument monitor_flags __attribute__((unused))
)
{
    rtems_monitor_server_request_t  request;
    rtems_monitor_server_response_t response;
    rtems_status_code               status;
    size_t                          size;

    for (;;)
    {
        status = rtems_message_queue_receive(
                        rtems_monitor_server_request_queue_id,
                        &request,
                        &size,
                        RTEMS_WAIT,
                        (rtems_interval) 0);

        if (status != RTEMS_SUCCESSFUL)
        {
            rtems_error(status, "monitor server msg queue receive error");
            goto failed;
        }

        if (size != sizeof(request))
        {
            rtems_error(0, "monitor server bad size on receive");
            goto failed;
        }

        switch (request.command)
        {
            case RTEMS_MONITOR_SERVER_CANONICAL:
            {
                rtems_monitor_object_type_t object_type;
                rtems_id            id;
                rtems_id            next_id;

                object_type = (rtems_monitor_object_type_t) request.argument0;
                id          = (rtems_id)            request.argument1;
                next_id = rtems_monitor_object_canonical_get(object_type,
                                                             id,
                                                             &response.payload,
                                                             &size);

                response.command = RTEMS_MONITOR_SERVER_RESPONSE;
                response.result0 = next_id;
                response.result1 = size;

#define SERVER_OVERHEAD  (offsetof(rtems_monitor_server_response_t, \
                                         payload))

                status = rtems_message_queue_send(request.return_id,
                                                  &response,
                                                  size + SERVER_OVERHEAD);
                if (status != RTEMS_SUCCESSFUL)
                {
                    rtems_error(status, "response send failed");
                    goto failed;
                }
                break;
            }

            default:
            {
                rtems_error(0, "invalid command to monitor server: %d", request.command);
                goto failed;
            }
        }
    }

failed:
    rtems_task_delete(RTEMS_SELF);
}
Пример #13
0
/* utility wrapper */
static void
spawned_shell(void *targ)
{
  rtems_status_code    sc;
  FILE                *nstd[3]={0};
  FILE                *ostd[3]={ stdin, stdout, stderr };
  int                  i=0;
  struct shell_args  *arg = targ;
  bool login_failed = false;
  bool start = true;

  sc=rtems_libio_set_private_env();

  /* newlib hack/workaround. Before we change stdin/out/err we must make
         * sure the internal data are initialized (fileno(stdout) has this sideeffect).
   * This should probably be done from RTEMS' libc support layer...
   * (T.S., newlibc-1.13; 2005/10)
         */

  fileno(stdout);

  if (RTEMS_SUCCESSFUL != sc) {
    rtems_error(sc,"rtems_libio_set_private_env");
    goto cleanup;
  }

  /* redirect stdio */
  for (i=0; i<3; i++) {
    if ( !(nstd[i]=fopen(arg->devname,"r+")) ) {
      perror("unable to open stdio");
      goto cleanup;
    }
  }

  stdin  = nstd[0];
  stdout = nstd[1];
  stderr = nstd[2];

  #if 0
    printk("STDOUT is now %x (%x) (FD %i/%i)\n",
           stdout,nstd[1],fileno(stdout),fileno(nstd[1]));
    printf("hello\n");
    write(fileno(stdout),"hellofd\n",8);
  #endif

  /* call their routine */
  if (rtems_telnetd_config.login_check != NULL) {
    start = rtems_shell_login_prompt(
      stdin,
      stderr,
      arg->devname,
      rtems_telnetd_config.login_check
    );
    login_failed = !start;
  }
  if (start) {
    rtems_telnetd_config.command( arg->devname, arg->arg);
  }

  stdin  = ostd[0];
  stdout = ostd[1];
  stderr = ostd[2];

  if (login_failed) {
    syslog(
      LOG_AUTHPRIV | LOG_WARNING,
      "telnetd: to many wrong passwords entered from %s",
      arg->peername
    );
  }

cleanup:
  release_a_Connection(arg->devname, arg->peername, nstd, i);
  free(arg);
}
Пример #14
0
static int rtems_verror(
    uint32_t     error_flag,
    const char   *printf_format,
    va_list      arglist
)
{
    int               local_errno = 0;
    int               chars_written = 0;
    rtems_status_code status;

    if (error_flag & RTEMS_ERROR_PANIC)
    {
        if (rtems_panic_in_progress++)
            _Thread_Disable_dispatch();       /* disable task switches */

        /* don't aggravate things */
        if (rtems_panic_in_progress > 2)
            return 0;
    }

    (void) fflush(stdout);  	    /* in case stdout/stderr same */

    status = error_flag & ~RTEMS_ERROR_MASK;
    if (error_flag & RTEMS_ERROR_ERRNO)     /* include errno? */
        local_errno = errno;

    #if defined(RTEMS_MULTIPROCESSING)
      if (_System_state_Is_multiprocessing)
        fprintf(stderr, "[%" PRIu32 "] ", _Configuration_MP_table->node);
    #endif

    chars_written += vfprintf(stderr, printf_format, arglist);

    if (status)
        chars_written += fprintf(stderr, " (status: %s)", rtems_status_text(status));

    if (local_errno)
    {
      if ((local_errno > 0) && *strerror(local_errno))
        chars_written += fprintf(stderr, " (errno: %s)", strerror(local_errno));
      else
        chars_written += fprintf(stderr, " (unknown errno=%d)", local_errno);
    }

    chars_written += fprintf(stderr, "\n");

    (void) fflush(stderr);

    if (error_flag & (RTEMS_ERROR_PANIC | RTEMS_ERROR_ABORT))
    {
        if (error_flag & RTEMS_ERROR_PANIC)
        {
            rtems_error(0, "fatal error, exiting");
            _exit(local_errno);
        }
        else
        {
            rtems_error(0, "fatal error, aborting");
            abort();
        }
    }
    return chars_written;
}