source: rtems/cpukit/libmisc/shell/shell.c @ 5f0ab5cf

4.115
Last change on this file since 5f0ab5cf was 5f0ab5cf, checked in by Sebastian Huber <sebastian.huber@…>, on 05/28/14 at 15:17:29

shell: Make rtems_global_shell_env public

Provide rtems_global_shell_env as a public read-only variable for
backward compatibility.

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