source: rtems/cpukit/libmisc/shell/shell.c @ cbd1e87

4.104.115
Last change on this file since cbd1e87 was cbd1e87, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on 04/14/09 at 08:50:03

adapt copyright statements

  • Property mode set to 100644
File size: 25.0 KB
RevLine 
[dd74e612]1/*
2 *
3 *  Instantatiate a new terminal shell.
4 *
[aed742c]5 *  Author:
[dd74e612]6 *
[aed742c]7 *   WORK: fernando.ruiz@ctv.es
[dd74e612]8 *   HOME: correo@fernando-ruiz.com
9 *
[4e5299f]10 *  The license and distribution terms for this file may be
11 *  found in the file LICENSE in this distribution or at
12 *  http://www.rtems.com/license/LICENSE.
[dd74e612]13 *
14 *  $Id$
15 */
[814d9588]16
[b2712e3]17#ifdef HAVE_CONFIG_H
18#include "config.h"
19#endif
[dd74e612]20
21#include <stdio.h>
[84206479]22#include <time.h>
[dd74e612]23
24#include <rtems.h>
25#include <rtems/error.h>
26#include <rtems/libio.h>
[aed742c]27#include <rtems/libio_.h>
28#include <rtems/system.h>
[b2712e3]29#include <rtems/shell.h>
[4e5299f]30#include <rtems/shellconfig.h>
[06f8e558]31#include <rtems/console.h>
[4e5299f]32#include "internal.h"
[dd74e612]33
34#include <termios.h>
35#include <string.h>
36#include <stdlib.h>
37#include <ctype.h>
[70d689a]38#include <sys/stat.h>
[dd74e612]39#include <unistd.h>
40#include <errno.h>
[b2712e3]41#include <pwd.h>
[dd74e612]42
[8a775c27]43rtems_shell_env_t rtems_global_shell_env = {
[06f8e558]44  .magic         = rtems_build_name('S', 'E', 'N', 'V'),
45  .devname       = CONSOLE_DEVICE_NAME,
46  .taskname      = "SHGL",
47  .exit_shell    = false,
48  .forever       = true,
49  .errorlevel    = -1,
50  .echo          = false,
51  .cwd           = "/",
52  .input         = NULL,
53  .output        = NULL,
54  .output_append = false,
55  .wake_on_end   = RTEMS_ID_NONE,
[8a775c27]56  .login_check   = NULL
[06f8e558]57};
58
59rtems_shell_env_t *rtems_current_shell_env = &rtems_global_shell_env;
[4e5299f]60
61/*
[814d9588]62 *  Initialize the shell user/process environment information
[4e5299f]63 */
[2eeb648c]64rtems_shell_env_t *rtems_shell_init_env(
[06f8e558]65  rtems_shell_env_t *shell_env
[4e5299f]66)
67{
[814d9588]68  if ( !shell_env ) {
[2eeb648c]69    shell_env = malloc(sizeof(rtems_shell_env_t));
[814d9588]70    if ( !shell_env )
[be8ab6a]71      return NULL;
[1ff9922]72    *shell_env = rtems_global_shell_env;
73    shell_env->taskname = NULL;
[4e5299f]74  }
75
[814d9588]76  return shell_env;
[dd74e612]77}
[4e5299f]78
[798ff5a]79/*
80 *  Completely free a shell_env_t and all associated memory
81 */
82void rtems_shell_env_free(
83  void *ptr
84)
85{
86  rtems_shell_env_t *shell_env;
87  shell_env = (rtems_shell_env_t *) ptr;
88
89  if ( !ptr )
90    return;
91
92  if ( shell_env->input )
93    free((void *)shell_env->input);
94  if ( shell_env->output )
95    free((void *)shell_env->output);
96  free( ptr );
97}
98
[814d9588]99/*
100 *  Get a line of user input with modest features
101 */
[ea90df23]102int rtems_shell_line_editor(
103  char       *cmds[],
104  int         count,
105  int         size,
106  const char *prompt,
107  FILE       *in,
108  FILE       *out
109)
110{
111  unsigned int extended_key;
[7c4cdeb9]112  int          c;
[ea90df23]113  int          col;
114  int          last_col;
115  int          output;
116  char         line[size];
117  char         new_line[size];
118  int          up;
119  int          cmd = -1;
120  int          inserting = 1;
[8a775c27]121
[ea90df23]122  output = (out && isatty(fileno(in)));
123
124  col = last_col = 0;
[8a775c27]125
[ea90df23]126  tcdrain(fileno(in));
127  if (out)
128    tcdrain(fileno(out));
129
130  if (output && prompt)
131    fprintf(out, "\r%s", prompt);
[8a775c27]132
[ea90df23]133  line[0] = 0;
134  new_line[0] = 0;
[8a775c27]135
[ea90df23]136  for (;;) {
[8a775c27]137
[ea90df23]138    if (output)
139      fflush(out);
140
141    extended_key = rtems_shell_getchar(in);
142
143    if (extended_key == EOF)
144      return -2;
[8a775c27]145
[ea90df23]146    c = extended_key & RTEMS_SHELL_KEYS_NORMAL_MASK;
[8a775c27]147
[ea90df23]148    /*
149     * Make the extended_key usable as a boolean.
150     */
151    extended_key &= ~RTEMS_SHELL_KEYS_NORMAL_MASK;
[8a775c27]152
[ea90df23]153    up = 0;
[8a775c27]154
[ea90df23]155    if (extended_key)
156    {
157      switch (c)
158      {
159        case RTEMS_SHELL_KEYS_END:
160          if (output)
161            fprintf(out,line + col);
162          col = (int) strlen (line);
163          break;
164
165        case RTEMS_SHELL_KEYS_HOME:
166          if (output) {
167            if (prompt)
168              fprintf(out,"\r%s", prompt);
169          }
170          col = 0;
171          break;
172
173        case RTEMS_SHELL_KEYS_LARROW:
174          if (col > 0)
175          {
176            col--;
177            if (output)
178              fputc('\b', out);
179          }
180          break;
181
182          case RTEMS_SHELL_KEYS_RARROW:
183            if ((col < size) && (line[col] != '\0'))
184            {
185              if (output)
186                fprintf(out, "%c", line[col]);
187              col++;
188            }
189            break;
190
191        case RTEMS_SHELL_KEYS_UARROW:
192          if ((cmd >= (count - 1)) || (strlen(cmds[cmd + 1]) == 0)) {
193            if (output)
194              fputc('\x7', out);
195            break;
196          }
197
198          up = 1;
199
200          /* drop through */
201        case RTEMS_SHELL_KEYS_DARROW:
[8a775c27]202
[ea90df23]203        {
204          int last_cmd = cmd;
205          int clen = strlen (line);
206
207          if (prompt)
208            clen += strlen(prompt);
[8a775c27]209
[ea90df23]210          if (up) {
211            cmd++;
212          } else {
213            if (cmd < 0) {
214              if (output)
215                fprintf(out, "\x7");
216              break;
217            }
218            else
219              cmd--;
220          }
221
222          if ((last_cmd < 0) || (strcmp(cmds[last_cmd], line) != 0))
223            memcpy (new_line, line, size);
224
225          if (cmd < 0)
226            memcpy (line, new_line, size);
227          else
228            memcpy (line, cmds[cmd], size);
[8a775c27]229
[ea90df23]230          col = strlen (line);
[8a775c27]231
[ea90df23]232          if (output) {
233            fprintf(out,"\r%*c", clen, ' ');
234            fprintf(out,"\r%s%s", prompt, line);
235          }
236          else {
237            if (output)
238              fputc('\x7', out);
239          }
240        }
241        break;
242
243        case RTEMS_SHELL_KEYS_DEL:
244          if (line[col] != '\0')
245          {
246            int end;
247            int bs;
248            strcpy (&line[col], &line[col + 1]);
249            if (output) {
250              fprintf(out,"\r%s%s ", prompt, line);
251              end = (int) strlen (line);
252              for (bs = 0; bs < ((end - col) + 1); bs++)
253                fputc('\b', out);
254            }
255          }
256          break;
257
258        case RTEMS_SHELL_KEYS_INS:
259          inserting = inserting ? 0 : 1;
260          break;
261      }
262    }
263    else
264    {
265      switch (c)
266      {
267        case 1:/*Control-a*/
268          if (output) {
269            if (prompt)
270              fprintf(out,"\r%s", prompt);
271          }
272          col = 0;
273          break;
[8a775c27]274
[ea90df23]275        case 5:/*Control-e*/
276          if (output)
277            fprintf(out,line + col);
278          col = (int) strlen (line);
279          break;
280
281        case 11:/*Control-k*/
282          if (line[col]) {
283            if (output) {
284              int end = strlen(line);
285              int bs;
286              fprintf(out,"%*c", end - col, ' ');
287              for (bs = 0; bs < (end - col); bs++)
288                fputc('\b', out);
289            }
290            line[col] = '\0';
291          }
292          break;
[8a775c27]293
[ea90df23]294        case 0x04:/*Control-d*/
295          if (strlen(line))
296            break;
297        case EOF:
298          if (output)
[8c422e2]299            fputc('\n', out);
[ea90df23]300          return -2;
[8a775c27]301
[ea90df23]302        case '\f':
303          if (output) {
304            int end;
305            int bs;
306            fputc('\f',out);
307            fprintf(out,"\r%s%s", prompt, line);
308            end = (int) strlen (line);
309            for (bs = 0; bs < (end - col); bs++)
310              fputc('\b', out);
311          }
312          break;
313
314        case '\b':
315        case '\x7f':
316          if (col > 0)
317          {
318            int bs;
319            col--;
320            strcpy (line + col, line + col + 1);
321            if (output) {
322              fprintf(out,"\b%s \b", line + col);
323              for (bs = 0; bs < ((int) strlen (line) - col); bs++)
324                fputc('\b', out);
325            }
326          }
327          break;
328
329        case '\n':
330        case '\r':
331        {
332          /*
333           * Process the command.
334           */
335          if (output)
336            fprintf(out,"\n");
[8a775c27]337
[ea90df23]338          /*
339           * Only process the command if we have a command and it is not
340           * repeated in the history.
341           */
342          if (strlen(line) == 0) {
343            cmd = -1;
344          } else {
345            if ((cmd < 0) || (strcmp(line, cmds[cmd]) != 0)) {
346              if (count > 1)
347                memmove(cmds[1], cmds[0], (count - 1) * size);
348              memmove (cmds[0], line, size);
349              cmd = 0;
350            }
351          }
352        }
353        return cmd;
354
355        default:
[7311863]356          if ((col < (size - 1)) && (c >= ' ') && (c <= '~')) {
[ea90df23]357            int end = strlen (line);
358            if (inserting && (col < end) && (end < size)) {
359              int ch, bs;
360              for (ch = end + 1; ch > col; ch--)
361                line[ch] = line[ch - 1];
362              if (output) {
363                fprintf(out, line + col);
364                for (bs = 0; bs < (end - col + 1); bs++)
365                  fputc('\b', out);
366              }
367            }
368            line[col++] = c;
369            if (col > end)
370              line[col] = '\0';
371            if (output)
372              fputc(c, out);
373          }
374          break;
375      }
376    }
377  }
378  return -2;
379}
380
[dd74e612]381/* ----------------------------------------------- *
[aed742c]382 * - The shell TASK
[dd74e612]383 * Poor but enough..
384 * TODO: Redirection. Tty Signals. ENVVARs. Shell language.
385 * ----------------------------------------------- */
386
[1167235]387void rtems_shell_init_issue(void)
388{
389  static bool issue_inited=false;
[814d9588]390  struct stat buf;
[dd74e612]391
[814d9588]392  if (issue_inited)
393    return;
[1167235]394  issue_inited = true;
[70d689a]395
[814d9588]396  /* dummy call to init /etc dir */
397  getpwnam("root");
398
399  if (stat("/etc/issue",&buf)) {
[2eeb648c]400    rtems_shell_write_file("/etc/issue",
[1fae7b43]401                           "\n"
[2eeb648c]402                           "Welcome to @V\\n"
403                           "Login into @S\\n");
[814d9588]404  }
405
406  if (stat("/etc/issue.net",&buf)) {
[2eeb648c]407     rtems_shell_write_file("/etc/issue.net",
[1fae7b43]408                           "\n"
[2eeb648c]409                            "Welcome to %v\n"
410                            "running on %m\n");
[814d9588]411  }
[70d689a]412}
413
[8a775c27]414static bool rtems_shell_login(FILE * in,FILE * out) {
[6dd411aa]415  FILE          *fd;
416  int            c;
417  time_t         t;
418  int            times;
419  char           name[128];
420  char           pass[128];
421  struct passwd *passwd;
422
[2eeb648c]423  rtems_shell_init_issue();
[6dd411aa]424  setuid(0);
425  setgid(0);
426  rtems_current_user_env->euid =
427  rtems_current_user_env->egid =0;
428
429  if (out) {
[2eeb648c]430    if ((rtems_current_shell_env->devname[5]!='p')||
431        (rtems_current_shell_env->devname[6]!='t')||
432        (rtems_current_shell_env->devname[7]!='y')) {
[6dd411aa]433      fd = fopen("/etc/issue","r");
434      if (fd) {
435        while ((c=fgetc(fd))!=EOF) {
436          if (c=='@')  {
437            switch(c=fgetc(fd)) {
438              case 'L':
[2eeb648c]439                fprintf(out,"%s",rtems_current_shell_env->devname);
[6dd411aa]440                break;
441              case 'B':
442                fprintf(out,"0");
443                break;
[70d689a]444              case 'T':
[6dd411aa]445              case 'D':
446                time(&t);
447                fprintf(out,"%s",ctime(&t));
448                break;
449              case 'S':
450                fprintf(out,"RTEMS");
451                break;
452              case 'V':
[a3ddb08b]453                fprintf(out,"%s\n%s",_RTEMS_version, _Copyright_Notice);
[6dd411aa]454                break;
455              case '@':
456                fprintf(out,"@");
457                break;
458              default :
459                fprintf(out,"@%c",c);
460                break;
461            }
462          } else if (c=='\\')  {
463            switch(c=fgetc(fd)) {
464              case '\\': fprintf(out,"\\"); break;
465              case 'b':  fprintf(out,"\b"); break;
466              case 'f':  fprintf(out,"\f"); break;
467              case 'n':  fprintf(out,"\n"); break;
468              case 'r':  fprintf(out,"\r"); break;
469              case 's':  fprintf(out," ");  break;
470              case 't':  fprintf(out,"\t"); break;
471              case '@':  fprintf(out,"@");  break;
472            }
473          } else {
474            fputc(c,out);
475          }
476        }
477        fclose(fd);
478      }
479    } else {
480      fd = fopen("/etc/issue.net","r");
481      if (fd) {
482        while ((c=fgetc(fd))!=EOF) {
483          if (c=='%')  {
484            switch(c=fgetc(fd)) {
485              case 't':
[2eeb648c]486                fprintf(out,"%s",rtems_current_shell_env->devname);
[6dd411aa]487                break;
488              case 'h':
489                fprintf(out,"0");
490                break;
491              case 'D':
492                fprintf(out," ");
493                break;
494              case 'd':
495                time(&t);
496                fprintf(out,"%s",ctime(&t));
497                break;
498              case 's':
499                fprintf(out,"RTEMS");
500                break;
501              case 'm':
502                fprintf(out,"(" CPU_NAME "/" CPU_MODEL_NAME ")");
503                break;
504              case 'r':
505                fprintf(out,_RTEMS_version);
506                break;
507              case 'v':
508                fprintf(out,"%s\n%s",_RTEMS_version,_Copyright_Notice);
509                break;
510              case '%':fprintf(out,"%%");
511                break;
512              default:
513                fprintf(out,"%%%c",c);
514                break;
515            }
516          } else {
517            fputc(c,out);
518          }
519        }
520        fclose(fd);
521      }
522    }
523  }
524
[8a775c27]525  return rtems_shell_login_prompt(
526    in,
527    out,
528    rtems_current_shell_env->devname,
529    rtems_current_shell_env->login_check
530  );
[b2712e3]531}
532
[814d9588]533#if defined(SHELL_DEBUG)
[2eeb648c]534void rtems_shell_print_env(
535  rtems_shell_env_t * shell_env
[6dd411aa]536)
537{
538  if ( !shell_env ) {
539    printk( "shell_env is NULL\n" );
540    return;
541  }
542  printk( "shell_env=%p\n"
543    "shell_env->magic=0x%08x\t"
544    "shell_env->devname=%s\n"
545    "shell_env->taskname=%s\t"
546    "shell_env->exit_shell=%d\t"
547    "shell_env->forever=%d\n",
548    shell_env->magic,
549    shell_env->devname,
550    ((shell_env->taskname) ? shell_env->taskname : "NOT SET"),
551    shell_env->exit_shell,
552    shell_env->forever
553  );
554}
555#endif
[dd74e612]556
[8e30a269]557rtems_task rtems_shell_task(rtems_task_argument task_argument)
[6dd411aa]558{
[1ff9922]559  rtems_shell_env_t *shell_env = (rtems_shell_env_t*) task_argument;
560  rtems_id           wake_on_end = shell_env->wake_on_end;
561  rtems_shell_main_loop( shell_env );
562  if (wake_on_end != RTEMS_INVALID_ID)
563    rtems_event_send (wake_on_end, RTEMS_EVENT_1);
564  rtems_task_delete( RTEMS_SELF );
[6dd411aa]565}
[dd74e612]566
[ea90df23]567#define RTEMS_SHELL_MAXIMUM_ARGUMENTS (128)
568#define RTEMS_SHELL_CMD_SIZE          (128)
569#define RTEMS_SHELL_CMD_COUNT         (32)
570#define RTEMS_SHELL_PROMPT_SIZE       (128)
[aed742c]571
[1167235]572bool rtems_shell_main_loop(
[2eeb648c]573  rtems_shell_env_t *shell_env_arg
[798ff5a]574)
[6dd411aa]575{
[2eeb648c]576  rtems_shell_env_t *shell_env;
577  rtems_shell_cmd_t *shell_cmd;
[6dd411aa]578  rtems_status_code  sc;
579  struct termios     term;
[8084ce80]580  struct termios     previous_term;
[ea90df23]581  char              *prompt = NULL;
582  int                cmd;
583  int                cmd_count = 1; /* assume a script and so only 1 command line */
584  char              *cmds[RTEMS_SHELL_CMD_COUNT];
[8c422e2]585  char              *cmd_argv;
[6dd411aa]586  int                argc;
[2eeb648c]587  char              *argv[RTEMS_SHELL_MAXIMUM_ARGUMENTS];
[1167235]588  bool               result = true;
[ff90595]589  bool               input_file = false;
[1ff9922]590  int                line = 0;
[a3ddb08b]591  FILE              *stdinToClose = NULL;
592  FILE              *stdoutToClose = NULL;
[2eeb648c]593
594  rtems_shell_initialize_command_set();
595
[798ff5a]596  shell_env =
597  rtems_current_shell_env = rtems_shell_init_env( shell_env_arg );
[8a775c27]598
[2eeb648c]599  /*
600   * @todo chrisj
[1ff9922]601   * Remove the use of task variables. Change to have a single
[2eeb648c]602   * allocation per shell and then set into a notepad register
[1ff9922]603   * in the TCB. Provide a function to return the pointer.
[2eeb648c]604   * Task variables are a virus to embedded systems software.
605   */
[798ff5a]606  sc = rtems_task_variable_add(
607    RTEMS_SELF,
608    (void*)&rtems_current_shell_env,
609    rtems_shell_env_free
610  );
[6dd411aa]611  if (sc != RTEMS_SUCCESSFUL) {
612    rtems_error(sc,"rtems_task_variable_add(current_shell_env):");
[1167235]613    return false;
[814d9588]614  }
[dd74e612]615
[b2712e3]616  setuid(0);
617  setgid(0);
[ea90df23]618
619  rtems_current_user_env->euid = rtems_current_user_env->egid = 0;
[6dd411aa]620
[1ff9922]621  fileno(stdout);
622
[8a775c27]623  /* fprintf( stderr,
[a3ddb08b]624     "-%s-%s-\n", shell_env->input, shell_env->output );
[ea90df23]625  */
[be8ab6a]626
627  if (shell_env->output && strcmp(shell_env->output, "stdout") != 0) {
[1ff9922]628    if (strcmp(shell_env->output, "stderr") == 0) {
629      stdout = stderr;
630    } else if (strcmp(shell_env->output, "/dev/null") == 0) {
631      fclose (stdout);
632    } else {
633      FILE *output = fopen(shell_env_arg->output,
634                           shell_env_arg->output_append ? "a" : "w");
635      if (!output) {
636        fprintf(stderr, "shell: open output %s failed: %s\n",
637                shell_env_arg->output, strerror(errno));
[1167235]638        return false;
[1ff9922]639      }
640      stdout = output;
[a3ddb08b]641      stdoutToClose = output;
[1ff9922]642    }
643  }
[8a775c27]644
[be8ab6a]645  if (shell_env->input && strcmp(shell_env_arg->input, "stdin") != 0) {
[1ff9922]646    FILE *input = fopen(shell_env_arg->input, "r");
647    if (!input) {
648      fprintf(stderr, "shell: open input %s failed: %s\n",
649              shell_env_arg->input, strerror(errno));
[1167235]650      return false;
[1ff9922]651    }
652    stdin = input;
[a3ddb08b]653    stdinToClose = input;
[1167235]654    shell_env->forever = false;
655    input_file =true;
[1ff9922]656  }
657  else {
658    /* make a raw terminal,Linux Manuals */
[8084ce80]659    if (tcgetattr(fileno(stdin), &previous_term) >= 0) {
660      term = previous_term;
[1ff9922]661      term.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
662      term.c_oflag &= ~OPOST;
663      term.c_oflag |= (OPOST|ONLCR); /* But with cr+nl on output */
664      term.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
665      term.c_cflag  |= CLOCAL | CREAD;
666      term.c_cc[VMIN]  = 1;
667      term.c_cc[VTIME] = 0;
668      if (tcsetattr (fileno(stdin), TCSADRAIN, &term) < 0) {
669        fprintf(stderr,
670                "shell:cannot set terminal attributes(%s)\n",shell_env->devname);
671      }
[814d9588]672    }
[ea90df23]673    cmd_count = RTEMS_SHELL_CMD_COUNT;
674    prompt = malloc(RTEMS_SHELL_PROMPT_SIZE);
675    if (!prompt)
676        fprintf(stderr,
677                "shell:cannot allocate prompt memory\n");
[6dd411aa]678  }
679
[1ff9922]680  setvbuf(stdin,NULL,_IONBF,0); /* Not buffered*/
681  setvbuf(stdout,NULL,_IONBF,0); /* Not buffered*/
682
[2eeb648c]683  rtems_shell_initialize_command_set();
[8a775c27]684
[ea90df23]685  /*
686   * Allocate the command line buffers.
687   */
[8c422e2]688  cmd_argv = malloc (RTEMS_SHELL_CMD_SIZE);
689  if (!cmd_argv) {
690    fprintf(stderr, "no memory for command line buffers\n" );
691  }
[8a775c27]692
[ea90df23]693  cmds[0] = calloc (cmd_count, RTEMS_SHELL_CMD_SIZE);
694  if (!cmds[0]) {
695    fprintf(stderr, "no memory for command line buffers\n" );
696  }
[8c422e2]697
698  if (cmd_argv && cmds[0]) {
[ea90df23]699
700    memset (cmds[0], 0, cmd_count * RTEMS_SHELL_CMD_SIZE);
701
702    for (cmd = 1; cmd < cmd_count; cmd++) {
703      cmds[cmd] = cmds[cmd - 1] + RTEMS_SHELL_CMD_SIZE;
[6dd411aa]704    }
[8a775c27]705
[ea90df23]706    do {
707      /* Set again root user and root filesystem, side effect of set_priv..*/
708      sc = rtems_libio_set_private_env();
709      if (sc != RTEMS_SUCCESSFUL) {
710        rtems_error(sc,"rtems_libio_set_private_env():");
[1167235]711        result = false;
[ea90df23]712        break;
[1ff9922]713      }
[7c4cdeb9]714
715      /*
716       *  By using result here, we can fall to the bottom of the
717       *  loop when the connection is dropped during login and
718       *  keep on trucking.
719       */
[8a775c27]720      if (shell_env->login_check != NULL) {
721        result = rtems_shell_login(stdin,stdout);
[7c4cdeb9]722      } else {
[06f8e558]723        result = true;
[7c4cdeb9]724      }
725
726      if (result)  {
[ea90df23]727        const char *c;
728        memset (cmds[0], 0, cmd_count * RTEMS_SHELL_CMD_SIZE);
[1ff9922]729        if (!input_file) {
[ea90df23]730          rtems_shell_cat_file(stdout,"/etc/motd");
731          fprintf(stdout, "\n"
732                  "RTEMS SHELL (Ver.1.0-FRC):%s. " \
733                  __DATE__". 'help' to list commands.\n",
734                  shell_env->devname);
[1ff9922]735        }
[55c64fc9]736
737        if (input_file)
738          chdir(shell_env->cwd);
739        else
740          chdir("/"); /* XXX: chdir to getpwent homedir */
[8a775c27]741
[1167235]742        shell_env->exit_shell = false;
[ea90df23]743
744        for (;;) {
745          int cmd;
[8a775c27]746
[ea90df23]747          /* Prompt section */
748          if (prompt) {
749            rtems_shell_get_prompt(shell_env, prompt,
750                                   RTEMS_SHELL_PROMPT_SIZE);
751          }
[8a775c27]752
[ea90df23]753          /* getcmd section */
754          cmd = rtems_shell_line_editor(cmds, cmd_count,
755                                        RTEMS_SHELL_CMD_SIZE, prompt,
756                                        stdin, stdout);
757
758          if (cmd == -1)
759            continue; /* empty line */
[8a775c27]760
[ea90df23]761          if (cmd == -2)
762            break; /*EOF*/
763
764          line++;
765
[55c64fc9]766          if (shell_env->echo)
767            fprintf(stdout, "%d: %s\n", line, cmds[cmd]);
[8a775c27]768
[ea90df23]769          /* evaluate cmd section */
770          c = cmds[cmd];
771          while (*c) {
772            if (!isblank(*c))
773              break;
774            c++;
775          }
[1ff9922]776
[ea90df23]777          if (*c == '\0')   /* empty line */
778            continue;
[a5de1ef]779
[ea90df23]780          if (*c == '#') {  /* comment character */
781            cmds[cmd][0] = 0;
782            continue;
783          }
[1ff9922]784
[ea90df23]785          if (!strcmp(cmds[cmd],"bye") || !strcmp(cmds[cmd],"exit")) {
786            fprintf(stdout, "Shell exiting\n" );
787            break;
788          } else if (!strcmp(cmds[cmd],"shutdown")) { /* exit application */
789            fprintf(stdout, "System shutting down at user request\n" );
790            exit(0);
791          }
[6dd411aa]792
[ea90df23]793          /* exec cmd section */
794          /* TODO:
795           *  To avoid user crash catch the signals.
796           *  Open a new stdio files with posibility of redirection *
797           *  Run in a new shell task background. (unix &)
798           *  Resuming. A little bash.
799           */
[8c422e2]800          memcpy (cmd_argv, cmds[cmd], RTEMS_SHELL_CMD_SIZE);
801          if (!rtems_shell_make_args(cmd_argv, &argc, argv,
[ea90df23]802                                     RTEMS_SHELL_MAXIMUM_ARGUMENTS)) {
803            shell_cmd = rtems_shell_lookup_cmd(argv[0]);
804            if ( argv[0] == NULL ) {
805              shell_env->errorlevel = -1;
806            } else if ( shell_cmd == NULL ) {
807              shell_env->errorlevel = rtems_shell_script_file(argc, argv);
808            } else {
809              shell_env->errorlevel = shell_cmd->command(argc, argv);
810            }
[6dd411aa]811          }
[ea90df23]812
813          /* end exec cmd section */
814          if (shell_env->exit_shell)
815            break;
[6dd411aa]816        }
817
[ea90df23]818        fflush( stdout );
819        fflush( stderr );
[6dd411aa]820      }
[ea90df23]821    } while (result && shell_env->forever);
822
823  }
824
[8c422e2]825  if (cmds[0])
826    free (cmds[0]);
827  if (cmd_argv)
828    free (cmd_argv);
[798ff5a]829  if (prompt)
830    free (prompt);
831
[8084ce80]832  if (stdinToClose) {
[a3ddb08b]833    fclose( stdinToClose );
[8084ce80]834  } else {
[798ff5a]835    if (tcsetattr(fileno(stdin), TCSADRAIN, &previous_term) < 0) {
[8084ce80]836      fprintf(
837        stderr,
838        "shell: cannot reset terminal attributes (%s)\n",
839        shell_env->devname
840      );
841    }
842  }
[a3ddb08b]843  if ( stdoutToClose )
844    fclose( stdoutToClose );
[1ff9922]845  return result;
[dd74e612]846}
[6dd411aa]847
[dd74e612]848/* ----------------------------------------------- */
[cbd1e87]849static rtems_status_code rtems_shell_run (
850  const char *task_name,
851  size_t task_stacksize,
852  rtems_task_priority task_priority,
853  const char *devname,
854  bool forever,
855  bool wait,
856  const char *input,
857  const char *output,
858  bool output_append,
859  rtems_id wake_on_end,
860  bool echo,
861  rtems_shell_login_check_t login_check
[6dd411aa]862)
863{
864  rtems_id           task_id;
865  rtems_status_code  sc;
[2eeb648c]866  rtems_shell_env_t *shell_env;
[4e5299f]867  rtems_name         name;
868
[e41eaa88]869  if ( task_name && strlen(task_name) >= 4)
[814d9588]870    name = rtems_build_name(
871      task_name[0], task_name[1], task_name[2], task_name[3]);
[4e5299f]872  else
873    name = rtems_build_name( 'S', 'E', 'N', 'V' );
[6dd411aa]874
875  sc = rtems_task_create(
[4e5299f]876    name,
[6dd411aa]877    task_priority,
[4e5299f]878    task_stacksize,
[3899a537]879    RTEMS_PREEMPT | RTEMS_TIMESLICE | RTEMS_NO_ASR,
[6dd411aa]880    RTEMS_LOCAL | RTEMS_FLOATING_POINT,
881    &task_id
882  );
883  if (sc != RTEMS_SUCCESSFUL) {
884    rtems_error(sc,"creating task %s in shell_init()",task_name);
885    return sc;
886  }
887
[2eeb648c]888  shell_env = rtems_shell_init_env( NULL );
[6dd411aa]889  if ( !shell_env )  {
[1ff9922]890   rtems_error(RTEMS_NO_MEMORY,
891               "allocating shell_env %s in shell_init()",task_name);
[6dd411aa]892   return RTEMS_NO_MEMORY;
893  }
[1ff9922]894  shell_env->devname       = devname;
895  shell_env->taskname      = task_name;
[1167235]896  shell_env->exit_shell    = false;
[1ff9922]897  shell_env->forever       = forever;
[55c64fc9]898  shell_env->echo          = echo;
[1ff9922]899  shell_env->input         = strdup (input);
900  shell_env->output        = strdup (output);
901  shell_env->output_append = output_append;
902  shell_env->wake_on_end   = wake_on_end;
[8a775c27]903  shell_env->login_check   = login_check;
[6dd411aa]904
[55c64fc9]905  getcwd(shell_env->cwd, sizeof(shell_env->cwd));
906
[798ff5a]907  sc = rtems_task_start(task_id, rtems_shell_task,
[2eeb648c]908                          (rtems_task_argument) shell_env);
[798ff5a]909  if (sc != RTEMS_SUCCESSFUL) {
910    rtems_error(sc,"starting task %s in shell_init()",task_name);
911    return sc;
912  }
913
914  if (wait) {
915    rtems_event_set out;
916    sc = rtems_event_receive (RTEMS_EVENT_1, RTEMS_WAIT, 0, &out);
917  }
918
919  return 0;
[6dd411aa]920}
[1ff9922]921
[798ff5a]922rtems_status_code rtems_shell_init(
[cbd1e87]923  const char *task_name,
924  size_t task_stacksize,
925  rtems_task_priority task_priority,
926  const char *devname,
927  bool forever,
928  bool wait,
929  rtems_shell_login_check_t login_check
[1ff9922]930)
931{
[06f8e558]932  rtems_id to_wake = RTEMS_ID_NONE;
[798ff5a]933
934  if ( wait )
935    to_wake = rtems_task_self();
936
937  return rtems_shell_run(
938    task_name,               /* task_name */
939    task_stacksize,          /* task_stacksize */
940    task_priority,           /* task_priority */
941    devname,                 /* devname */
942    forever,                 /* forever */
943    wait,                    /* wait */
944    "stdin",                 /* input */
945    "stdout",                /* output */
[06f8e558]946    false,                   /* output_append */
[798ff5a]947    to_wake,                 /* wake_on_end */
[06f8e558]948    false,                   /* echo */
[8a775c27]949    login_check              /* login check */
[798ff5a]950  );
[1ff9922]951}
952
953rtems_status_code   rtems_shell_script (
[e41eaa88]954  const char          *task_name,
[06f8e558]955  size_t               task_stacksize,
[1ff9922]956  rtems_task_priority  task_priority,
957  const char*          input,
958  const char*          output,
[06f8e558]959  bool                 output_append,
960  bool                 wait,
961  bool                 echo
[1ff9922]962)
963{
964  rtems_id          current_task = RTEMS_INVALID_ID;
965  rtems_status_code sc;
966
967  if (wait) {
968    sc = rtems_task_ident (RTEMS_SELF, RTEMS_LOCAL, &current_task);
969    if (sc != RTEMS_SUCCESSFUL)
970      return sc;
971  }
[8a775c27]972
[798ff5a]973  sc = rtems_shell_run(
974    task_name,       /* task_name */
975    task_stacksize,  /* task_stacksize */
976    task_priority,   /* task_priority */
977    NULL,            /* devname */
978    0,               /* forever */
979    wait,            /* wait */
980    input,           /* input */
981    output,          /* output */
982    output_append,   /* output_append */
983    current_task,    /* wake_on_end */
[06f8e558]984    echo,            /* echo */
[8a775c27]985    NULL             /* login check */
[798ff5a]986  );
[1ff9922]987  if (sc != RTEMS_SUCCESSFUL)
988    return sc;
989
990  return sc;
991}
Note: See TracBrowser for help on using the repository browser.