source: rtems/cpukit/libmisc/shell/shell.c @ 89fd08e

4.11
Last change on this file since 89fd08e was 89fd08e, checked in by Chris Johns <chrisj@…>, on 08/14/17 at 04:50:55

libmisc/shell: Make some internal shell functions public.

  • Add 'rtems_shell_init_environment()' so a user can create the shell environment without needing to run a shell.
  • Move 'rtems_shell_lookup_topic', 'rtems_shell_can_see_cmd', and 'rtems_shell_execute_cmd' from the internal interface to the public interface.

Closes #3104.

  • Property mode set to 100644
File size: 28.0 KB
RevLine 
[dd74e612]1/*
2 *
3 *  Instantatiate a new terminal shell.
4 *
[aed742c]5 *  Author:
[dd74e612]6 *
[aed742c]7 *   WORK: fernando.ruiz@ctv.es
[dd74e612]8 *   HOME: correo@fernando-ruiz.com
9 *
[4e5299f]10 *  The license and distribution terms for this file may be
11 *  found in the file LICENSE in this distribution or at
[c499856]12 *  http://www.rtems.org/license/LICENSE.
[dd74e612]13 */
[814d9588]14
[b2712e3]15#ifdef HAVE_CONFIG_H
16#include "config.h"
17#endif
[dd74e612]18
19#include <stdio.h>
[84206479]20#include <time.h>
[dd74e612]21
22#include <rtems.h>
23#include <rtems/error.h>
24#include <rtems/libio.h>
[aed742c]25#include <rtems/libio_.h>
26#include <rtems/system.h>
[b2712e3]27#include <rtems/shell.h>
[4e5299f]28#include <rtems/shellconfig.h>
[06f8e558]29#include <rtems/console.h>
[4e5299f]30#include "internal.h"
[dd74e612]31
32#include <termios.h>
33#include <string.h>
34#include <stdlib.h>
35#include <ctype.h>
[70d689a]36#include <sys/stat.h>
[dd74e612]37#include <unistd.h>
38#include <errno.h>
[b2712e3]39#include <pwd.h>
[6cd4a5c]40#include <pthread.h>
41#include <assert.h>
[dd74e612]42
[5f0ab5cf]43const rtems_shell_env_t rtems_global_shell_env = {
[06f8e558]44  .magic         = rtems_build_name('S', 'E', 'N', 'V'),
45  .devname       = CONSOLE_DEVICE_NAME,
46  .taskname      = "SHGL",
47  .exit_shell    = false,
48  .forever       = true,
49  .errorlevel    = -1,
50  .echo          = false,
51  .cwd           = "/",
52  .input         = NULL,
53  .output        = NULL,
54  .output_append = false,
55  .wake_on_end   = RTEMS_ID_NONE,
[8a775c27]56  .login_check   = NULL
[06f8e558]57};
58
[373ccbb9]59static pthread_once_t rtems_shell_once = PTHREAD_ONCE_INIT;
60
[6cd4a5c]61static pthread_key_t rtems_shell_current_env_key;
[4e5299f]62
63/*
[814d9588]64 *  Initialize the shell user/process environment information
[4e5299f]65 */
[94547d1]66static rtems_shell_env_t *rtems_shell_init_env(
[13c37ad]67  rtems_shell_env_t *shell_env_p
[4e5299f]68)
69{
[13c37ad]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 ) {
[1ff9922]76    *shell_env = rtems_global_shell_env;
[13c37ad]77  } else {
78    *shell_env = *shell_env_p;
[4e5299f]79  }
[13c37ad]80  shell_env->taskname = NULL;
[4e5299f]81
[814d9588]82  return shell_env;
[dd74e612]83}
[4e5299f]84
[798ff5a]85/*
86 *  Completely free a shell_env_t and all associated memory
87 */
[94547d1]88static void rtems_shell_env_free(
[798ff5a]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
[373ccbb9]105static void rtems_shell_create_file(const char *name, const char *content)
[6cd4a5c]106{
[373ccbb9]107  FILE *fp = fopen(name, "wx");
108
109  if (fp != NULL) {
110    fputs(content, fp);
111    fclose(fp);
112  }
113}
114
[7840b66]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
[373ccbb9]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");
[7840b66]148
149  rtems_shell_init_commands();
[89fd08e]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);
[6cd4a5c]156}
157
158/*
159 *  Return the current shell environment
160 */
161rtems_shell_env_t *rtems_shell_get_current_env(void)
162{
[bb58190]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  }
[6cd4a5c]182}
183
[814d9588]184/*
185 *  Get a line of user input with modest features
186 */
[94547d1]187static int rtems_shell_line_editor(
[ea90df23]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;
[7c4cdeb9]197  int          c;
[ea90df23]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;
[8a775c27]206
[ea90df23]207  output = (out && isatty(fileno(in)));
208
209  col = last_col = 0;
[8a775c27]210
[ea90df23]211  tcdrain(fileno(in));
212  if (out)
213    tcdrain(fileno(out));
214
215  if (output && prompt)
216    fprintf(out, "\r%s", prompt);
[8a775c27]217
[ea90df23]218  line[0] = 0;
219  new_line[0] = 0;
[8a775c27]220
[ea90df23]221  for (;;) {
[8a775c27]222
[ea90df23]223    if (output)
224      fflush(out);
225
226    extended_key = rtems_shell_getchar(in);
227
228    if (extended_key == EOF)
229      return -2;
[8a775c27]230
[ea90df23]231    c = extended_key & RTEMS_SHELL_KEYS_NORMAL_MASK;
[8a775c27]232
[ea90df23]233    /*
234     * Make the extended_key usable as a boolean.
235     */
236    extended_key &= ~RTEMS_SHELL_KEYS_NORMAL_MASK;
[8a775c27]237
[ea90df23]238    up = 0;
[8a775c27]239
[ea90df23]240    if (extended_key)
241    {
242      switch (c)
243      {
244        case RTEMS_SHELL_KEYS_END:
245          if (output)
[8bca4fc]246            fprintf(out, "%s", line + col);
[ea90df23]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:
[22e98377]259          c = 2;
260          extended_key = 0;
[ea90df23]261          break;
262
[22e98377]263        case RTEMS_SHELL_KEYS_RARROW:
264          c = 6;
265          extended_key = 0;
266          break;
[ea90df23]267
268        case RTEMS_SHELL_KEYS_UARROW:
[22e98377]269          c = 16;
270          extended_key = 0;
271          break;
[ea90df23]272
273        case RTEMS_SHELL_KEYS_DARROW:
[22e98377]274          c = 14;
275          extended_key = 0;
276          break;
[ea90df23]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    }
[22e98377]298    if (!extended_key)
[ea90df23]299    {
300      switch (c)
301      {
[22e98377]302        case 1:                         /*Control-a*/
[ea90df23]303          if (output) {
304            if (prompt)
305              fprintf(out,"\r%s", prompt);
306          }
307          col = 0;
308          break;
[8a775c27]309
[22e98377]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*/
[ea90df23]340          if (output)
[8bca4fc]341            fprintf(out, "%s", line + col);
[ea90df23]342          col = (int) strlen (line);
343          break;
344
[22e98377]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) {
[06ac8b71]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), ' ');
[22e98377]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*/
[ea90df23]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;
[8a775c27]379
[ea90df23]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");
[8a775c27]415
[ea90df23]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;
[22e98377]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              }
[ea90df23]434            }
435          }
436        }
437        return cmd;
438
[22e98377]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
[ea90df23]521        default:
[7311863]522          if ((col < (size - 1)) && (c >= ' ') && (c <= '~')) {
[ea90df23]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) {
[8bca4fc]529                fprintf(out, "%s", line + col);
[ea90df23]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
[fa028bb]547static bool rtems_shell_login(rtems_shell_env_t *env, FILE * in,FILE * out)
548{
[bb58190]549  FILE              *fd;
550  int               c;
551  time_t            t;
552
[6dd411aa]553  if (out) {
[bb58190]554    if ((env->devname[5]!='p')||
555        (env->devname[6]!='t')||
556        (env->devname[7]!='y')) {
[6dd411aa]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':
[bb58190]563                fprintf(out,"%s", env->devname);
[6dd411aa]564                break;
565              case 'B':
566                fprintf(out,"0");
567                break;
[70d689a]568              case 'T':
[6dd411aa]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':
[a3ddb08b]577                fprintf(out,"%s\n%s",_RTEMS_version, _Copyright_Notice);
[6dd411aa]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':
[bb58190]610                fprintf(out,"%s", env->devname);
[6dd411aa]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
[bb58190]649  return rtems_shell_login_prompt(in, out, env->devname, env->login_check);
[b2712e3]650}
651
[814d9588]652#if defined(SHELL_DEBUG)
[2eeb648c]653void rtems_shell_print_env(
654  rtems_shell_env_t * shell_env
[6dd411aa]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
[dd74e612]675
[94547d1]676static rtems_task rtems_shell_task(rtems_task_argument task_argument)
[6dd411aa]677{
[1ff9922]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 );
[6dd411aa]684}
[dd74e612]685
[fa028bb]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
[ea90df23]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)
[aed742c]708
[1167235]709bool rtems_shell_main_loop(
[2eeb648c]710  rtems_shell_env_t *shell_env_arg
[798ff5a]711)
[6dd411aa]712{
[2eeb648c]713  rtems_shell_env_t *shell_env;
[6cd4a5c]714  int                eno;
[6dd411aa]715  struct termios     term;
[8084ce80]716  struct termios     previous_term;
[ea90df23]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];
[8c422e2]721  char              *cmd_argv;
[6dd411aa]722  int                argc;
[2eeb648c]723  char              *argv[RTEMS_SHELL_MAXIMUM_ARGUMENTS];
[1167235]724  bool               result = true;
[ff90595]725  bool               input_file = false;
[1ff9922]726  int                line = 0;
[a3ddb08b]727  FILE              *stdinToClose = NULL;
728  FILE              *stdoutToClose = NULL;
[2eeb648c]729
[89fd08e]730  rtems_shell_init_environment();
[7840b66]731
[6cd4a5c]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)");
[1167235]741    return false;
[814d9588]742  }
[dd74e612]743
[fa028bb]744  if (!rtems_shell_init_user_env()) {
745    rtems_error(0, "rtems_shell_init_user_env");
746    return false;
747  }
[6dd411aa]748
[1ff9922]749  fileno(stdout);
750
[8a775c27]751  /* fprintf( stderr,
[a3ddb08b]752     "-%s-%s-\n", shell_env->input, shell_env->output );
[ea90df23]753  */
[be8ab6a]754
755  if (shell_env->output && strcmp(shell_env->output, "stdout") != 0) {
[1ff9922]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));
[1167235]766        return false;
[1ff9922]767      }
768      stdout = output;
[a3ddb08b]769      stdoutToClose = output;
[1ff9922]770    }
771  }
[8a775c27]772
[be8ab6a]773  if (shell_env->input && strcmp(shell_env_arg->input, "stdin") != 0) {
[1ff9922]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));
[1167235]778      return false;
[1ff9922]779    }
780    stdin = input;
[a3ddb08b]781    stdinToClose = input;
[1167235]782    shell_env->forever = false;
783    input_file =true;
[1ff9922]784  }
785  else {
786    /* make a raw terminal,Linux Manuals */
[8084ce80]787    if (tcgetattr(fileno(stdin), &previous_term) >= 0) {
788      term = previous_term;
[1ff9922]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      }
[814d9588]800    }
[ea90df23]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");
[6dd411aa]806  }
807
[1ff9922]808  setvbuf(stdin,NULL,_IONBF,0); /* Not buffered*/
809  setvbuf(stdout,NULL,_IONBF,0); /* Not buffered*/
810
[ea90df23]811  /*
812   * Allocate the command line buffers.
813   */
[8c422e2]814  cmd_argv = malloc (RTEMS_SHELL_CMD_SIZE);
815  if (!cmd_argv) {
816    fprintf(stderr, "no memory for command line buffers\n" );
817  }
[8a775c27]818
[ea90df23]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  }
[8c422e2]823
824  if (cmd_argv && cmds[0]) {
[ea90df23]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;
[6dd411aa]830    }
[8a775c27]831
[ea90df23]832    do {
[fa028bb]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 {
[ffd5285]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
[fa028bb]850          result = true;
851        }
[7c4cdeb9]852      }
853
854      if (result)  {
[ea90df23]855        const char *c;
856        memset (cmds[0], 0, cmd_count * RTEMS_SHELL_CMD_SIZE);
[1ff9922]857        if (!input_file) {
[ea90df23]858          rtems_shell_cat_file(stdout,"/etc/motd");
859          fprintf(stdout, "\n"
[a2097c5]860                  "RTEMS Shell on %s. Use 'help' to list commands.\n",
[ea90df23]861                  shell_env->devname);
[1ff9922]862        }
[55c64fc9]863
864        if (input_file)
865          chdir(shell_env->cwd);
866        else
867          chdir("/"); /* XXX: chdir to getpwent homedir */
[8a775c27]868
[1167235]869        shell_env->exit_shell = false;
[ea90df23]870
871        for (;;) {
872          int cmd;
[8a775c27]873
[ea90df23]874          /* Prompt section */
875          if (prompt) {
876            rtems_shell_get_prompt(shell_env, prompt,
877                                   RTEMS_SHELL_PROMPT_SIZE);
878          }
[8a775c27]879
[ea90df23]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 */
[8a775c27]887
[ea90df23]888          if (cmd == -2)
889            break; /*EOF*/
890
891          line++;
892
[55c64fc9]893          if (shell_env->echo)
894            fprintf(stdout, "%d: %s\n", line, cmds[cmd]);
[8a775c27]895
[ea90df23]896          /* evaluate cmd section */
897          c = cmds[cmd];
898          while (*c) {
[bab5c5fa]899            if (!isblank((unsigned char)*c))
[ea90df23]900              break;
901            c++;
902          }
[1ff9922]903
[ea90df23]904          if (*c == '\0')   /* empty line */
905            continue;
[a5de1ef]906
[ea90df23]907          if (*c == '#') {  /* comment character */
908            cmds[cmd][0] = 0;
909            continue;
910          }
[1ff9922]911
[ea90df23]912          if (!strcmp(cmds[cmd],"bye") || !strcmp(cmds[cmd],"exit")) {
913            fprintf(stdout, "Shell exiting\n" );
914            break;
915          }
[6dd411aa]916
[ea90df23]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           */
[8c422e2]924          memcpy (cmd_argv, cmds[cmd], RTEMS_SHELL_CMD_SIZE);
925          if (!rtems_shell_make_args(cmd_argv, &argc, argv,
[ea90df23]926                                     RTEMS_SHELL_MAXIMUM_ARGUMENTS)) {
[5c141d6a]927            shell_env->errorlevel = rtems_shell_execute_cmd(argv[0], argc, argv);
[6dd411aa]928          }
[ea90df23]929
930          /* end exec cmd section */
931          if (shell_env->exit_shell)
932            break;
[6dd411aa]933        }
934
[ea90df23]935        fflush( stdout );
936        fflush( stderr );
[6dd411aa]937      }
[ea90df23]938    } while (result && shell_env->forever);
939
940  }
941
[8c422e2]942  if (cmds[0])
943    free (cmds[0]);
944  if (cmd_argv)
945    free (cmd_argv);
[798ff5a]946  if (prompt)
947    free (prompt);
948
[8084ce80]949  if (stdinToClose) {
[a3ddb08b]950    fclose( stdinToClose );
[8084ce80]951  } else {
[798ff5a]952    if (tcsetattr(fileno(stdin), TCSADRAIN, &previous_term) < 0) {
[8084ce80]953      fprintf(
954        stderr,
955        "shell: cannot reset terminal attributes (%s)\n",
956        shell_env->devname
957      );
958    }
959  }
[a3ddb08b]960  if ( stdoutToClose )
961    fclose( stdoutToClose );
[1ff9922]962  return result;
[dd74e612]963}
[6dd411aa]964
[dd74e612]965/* ----------------------------------------------- */
[cbd1e87]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
[6dd411aa]979)
980{
981  rtems_id           task_id;
982  rtems_status_code  sc;
[2eeb648c]983  rtems_shell_env_t *shell_env;
[4e5299f]984  rtems_name         name;
985
[e41eaa88]986  if ( task_name && strlen(task_name) >= 4)
[814d9588]987    name = rtems_build_name(
988      task_name[0], task_name[1], task_name[2], task_name[3]);
[4e5299f]989  else
990    name = rtems_build_name( 'S', 'E', 'N', 'V' );
[6dd411aa]991
992  sc = rtems_task_create(
[4e5299f]993    name,
[6dd411aa]994    task_priority,
[4e5299f]995    task_stacksize,
[3899a537]996    RTEMS_PREEMPT | RTEMS_TIMESLICE | RTEMS_NO_ASR,
[6dd411aa]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
[2eeb648c]1005  shell_env = rtems_shell_init_env( NULL );
[6dd411aa]1006  if ( !shell_env )  {
[1ff9922]1007   rtems_error(RTEMS_NO_MEMORY,
1008               "allocating shell_env %s in shell_init()",task_name);
[6dd411aa]1009   return RTEMS_NO_MEMORY;
1010  }
[1ff9922]1011  shell_env->devname       = devname;
1012  shell_env->taskname      = task_name;
[1167235]1013  shell_env->exit_shell    = false;
[1ff9922]1014  shell_env->forever       = forever;
[55c64fc9]1015  shell_env->echo          = echo;
[1ff9922]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;
[8a775c27]1020  shell_env->login_check   = login_check;
[ffd5285]1021  shell_env->uid           = getuid();
1022  shell_env->gid           = getgid();
[6dd411aa]1023
[55c64fc9]1024  getcwd(shell_env->cwd, sizeof(shell_env->cwd));
1025
[798ff5a]1026  sc = rtems_task_start(task_id, rtems_shell_task,
[2eeb648c]1027                          (rtems_task_argument) shell_env);
[798ff5a]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;
[6dd411aa]1039}
[1ff9922]1040
[798ff5a]1041rtems_status_code rtems_shell_init(
[cbd1e87]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
[1ff9922]1049)
1050{
[06f8e558]1051  rtems_id to_wake = RTEMS_ID_NONE;
[798ff5a]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 */
[06f8e558]1065    false,                   /* output_append */
[798ff5a]1066    to_wake,                 /* wake_on_end */
[06f8e558]1067    false,                   /* echo */
[8a775c27]1068    login_check              /* login check */
[798ff5a]1069  );
[1ff9922]1070}
1071
1072rtems_status_code   rtems_shell_script (
[e41eaa88]1073  const char          *task_name,
[06f8e558]1074  size_t               task_stacksize,
[1ff9922]1075  rtems_task_priority  task_priority,
1076  const char*          input,
1077  const char*          output,
[06f8e558]1078  bool                 output_append,
1079  bool                 wait,
1080  bool                 echo
[1ff9922]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  }
[8a775c27]1091
[798ff5a]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 */
[06f8e558]1103    echo,            /* echo */
[8a775c27]1104    NULL             /* login check */
[798ff5a]1105  );
[1ff9922]1106  if (sc != RTEMS_SUCCESSFUL)
1107    return sc;
1108
1109  return sc;
1110}
Note: See TracBrowser for help on using the repository browser.