source: rtems/cpukit/libmisc/shell/shell.c @ 2cec5ac

5
Last change on this file since 2cec5ac was 2cec5ac, checked in by Sebastian Huber <sebastian.huber@…>, on 03/12/18 at 09:29:21

shell: Fix rtems_shell_init_env()

Do not discard a user provided task name in rtems_shell_init_env().

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