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

4.115
Last change on this file since 5c141d6a was 5c141d6a, checked in by Sebastian Huber <sebastian.huber@…>, on 11/18/14 at 09:36:27

shell: Add and use rtems_shell_execute_cmd()

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