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

Last change on this file since cc060f0 was cc060f0, checked in by Sebastian Huber <sebastian.huber@…>, on May 10, 2019 at 12:38:28 PM

shell: Avoid rtems_error()

Do not use the rtems_error() function since this function pulls in
exit() and abort(). The abort() function pulls in raise() which pulls
in the whole POSIX signals support. This change saves about 16KiB of
text/rodata on ARM Thumb-2 systems.

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