source: rtems/cpukit/libmisc/shell/shell.c @ 3fe2155

Last change on this file since 3fe2155 was 3fe2155, checked in by Sebastian Huber <sebastian.huber@…>, on Feb 1, 2019 at 9:00:36 AM

Remove superfluous <rtems/system.h> includes

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