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

Last change on this file was 7260887, checked in by Chris Johns <chrisj@…>, on 12/13/23 at 02:42:23

libmisc/shell: Work around tmux bug in row and column

  • Extend the timeout to 150 msec for long remote sessions
  • Improve the performance of the detection

Closes #4975
Closes #4977

  • Property mode set to 100644
File size: 38.3 KB
RevLine 
[5f8c41c]1/**
2 * @file
[8425e67]3 *
[5f8c41c]4 * @brief Instantatiate a new terminal shell.
5 */
6
[dd74e612]7/*
[5f8c41c]8 * Copyright (c) 2001 Fernando Ruiz Casas <fruizcasas@gmail.com>
[dd74e612]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>
[d007cc2]23#include <rtems/error.h>
[dd74e612]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
[d007cc2]42#define SHELL_STD_DEBUG 0
43
44#if SHELL_STD_DEBUG
45#include <rtems/bspIo.h>
46#define shell_std_debug(...) \
47  do { printk("shell[%08x]: ", rtems_task_self()); printk(__VA_ARGS__); } while (0)
48#else
49#define shell_std_debug(...)
50#endif
51
[3407a3b]52#define SHELL_MAGIC rtems_build_name('S', 'E', 'N', 'V')
53
[5f0ab5cf]54const rtems_shell_env_t rtems_global_shell_env = {
[3407a3b]55  .magic         = SHELL_MAGIC,
[d007cc2]56  .managed       = false,
[06f8e558]57  .devname       = CONSOLE_DEVICE_NAME,
[e765cfb]58  .taskname      = "RTSH",
[06f8e558]59  .exit_shell    = false,
60  .forever       = true,
61  .echo          = false,
62  .cwd           = "/",
63  .input         = NULL,
64  .output        = NULL,
65  .output_append = false,
[d007cc2]66  .parent_stdin  = NULL,
67  .parent_stdout = NULL,
68  .parent_stderr = NULL,
[06f8e558]69  .wake_on_end   = RTEMS_ID_NONE,
[d007cc2]70  .exit_code     = NULL,
71  .login_check   = NULL,
72  .uid           = 0,
73  .gid           = 0
[06f8e558]74};
75
[d007cc2]76typedef struct rtems_shell_env_key_handle
77{
78  bool managed;
79  rtems_shell_env_t* env;
80} rtems_shell_env_key_handle;
81
[373ccbb9]82static pthread_once_t rtems_shell_once = PTHREAD_ONCE_INIT;
83
[6cd4a5c]84static pthread_key_t rtems_shell_current_env_key;
[4e5299f]85
86/*
[814d9588]87 *  Initialize the shell user/process environment information
[4e5299f]88 */
[94547d1]89static rtems_shell_env_t *rtems_shell_init_env(
[d007cc2]90  rtems_shell_env_t *shell_env_parent
[4e5299f]91)
92{
[13c37ad]93  rtems_shell_env_t *shell_env;
94
95  shell_env = malloc(sizeof(rtems_shell_env_t));
96  if ( !shell_env )
97    return NULL;
[d007cc2]98
99  if ( shell_env_parent == NULL ) {
100    shell_env_parent = rtems_shell_get_current_env();
101  }
102  if ( shell_env_parent == NULL ) {
[1ff9922]103    *shell_env = rtems_global_shell_env;
[13c37ad]104  } else {
[d007cc2]105    *shell_env = *shell_env_parent;
[4e5299f]106  }
[d007cc2]107  shell_env->managed = true;
108  shell_env->taskname = NULL;
[4e5299f]109
[814d9588]110  return shell_env;
[dd74e612]111}
[4e5299f]112
[798ff5a]113/*
114 *  Completely free a shell_env_t and all associated memory
115 */
[94547d1]116static void rtems_shell_env_free(
[798ff5a]117  void *ptr
118)
119{
[d007cc2]120  if ( ptr != NULL ) {
121    rtems_shell_env_key_handle *handle = (rtems_shell_env_key_handle *) ptr;
122    rtems_shell_env_t *shell_env = handle->env;
123
124    if ( handle->managed ) {
125      if ( shell_env->input )
126        free((void *)shell_env->input);
127      if ( shell_env->output )
128        free((void *)shell_env->output);
129      free( shell_env );
130    }
[798ff5a]131
[d007cc2]132    free( handle );
133  }
[798ff5a]134}
135
[373ccbb9]136static void rtems_shell_create_file(const char *name, const char *content)
[6cd4a5c]137{
[373ccbb9]138  FILE *fp = fopen(name, "wx");
139
140  if (fp != NULL) {
141    fputs(content, fp);
142    fclose(fp);
143  }
144}
145
[7840b66]146static void rtems_shell_init_commands(void)
147{
148  rtems_shell_cmd_t * const *c;
149  rtems_shell_alias_t * const *a;
150
151  for ( c = rtems_shell_Initial_commands ; *c  ; c++ ) {
152    rtems_shell_add_cmd_struct( *c );
153  }
154
155  for ( a = rtems_shell_Initial_aliases ; *a  ; a++ ) {
156    rtems_shell_alias_cmd( (*a)->name, (*a)->alias );
157  }
158}
159
[373ccbb9]160static void rtems_shell_init_once(void)
161{
162  struct passwd pwd;
163  struct passwd *pwd_res;
164
165  pthread_key_create(&rtems_shell_current_env_key, rtems_shell_env_free);
166
167  /* dummy call to init /etc dir */
168  getpwuid_r(0, &pwd, NULL, 0, &pwd_res);
169
170  rtems_shell_create_file("etc/issue",
171                          "\n"
172                          "Welcome to @V\\n"
173                          "Login into @S\\n");
174
175  rtems_shell_create_file("/etc/issue.net",
176                          "\n"
177                          "Welcome to %v\n"
178                          "running on %m\n");
[7840b66]179
180  rtems_shell_init_commands();
[2465c01]181  rtems_shell_register_monitor_commands();
182}
183
184void rtems_shell_init_environment(void)
185{
186  assert(pthread_once(&rtems_shell_once, rtems_shell_init_once) == 0);
[6cd4a5c]187}
188
[d007cc2]189/*
190 * Set the shell env into the current thread's shell key.
191 */
192static bool rtems_shell_set_shell_env(
193  rtems_shell_env_t* shell_env
194)
195{
196  /*
197   * The shell environment can be managed or it can be provided by a
198   * user. We need to create a handle to hold the env pointer.
199   */
200  rtems_shell_env_key_handle *handle;
201  int eno;
202
[a800e4de]203  rtems_shell_init_environment();
204
[d007cc2]205  handle = malloc(sizeof(rtems_shell_env_key_handle));
206  if (handle == NULL) {
207    rtems_error(0, "no memory for shell env key handle)");
208    return false;
209  }
210
211  handle->managed = shell_env->managed;
212  handle->env = shell_env;
213
214  eno = pthread_setspecific(rtems_shell_current_env_key, handle);
215  if (eno != 0) {
216    rtems_error(0, "pthread_setspecific(shell_current_env_key): set");
217    return false;
218  }
219
220  return true;
221}
222
223/*
224 * Clear the current thread's shell key.
225 */
226static void rtems_shell_clear_shell_env(void)
227{
228  int eno;
229
230  /*
231   * Run the destructor manually.
232   */
233  rtems_shell_env_free(pthread_getspecific(rtems_shell_current_env_key));
234
235  /*
236   * Clear the key
237   */
238  eno = pthread_setspecific(rtems_shell_current_env_key, NULL);
239  if (eno != 0)
240    rtems_error(0, "pthread_setspecific(shell_current_env_key): clear");
[20b1bdb]241}
[d007cc2]242
[20b1bdb]243/*
244 * Clear stdin, stdout and stderr file pointers so they will not be closed.
245 */
246static void rtems_shell_clear_shell_std_handles(void)
247{
[d007cc2]248  stdin = NULL;
249  stdout = NULL;
[20b1bdb]250  stderr = NULL;
[d007cc2]251}
252
[6cd4a5c]253/*
254 *  Return the current shell environment
255 */
256rtems_shell_env_t *rtems_shell_get_current_env(void)
257{
[d007cc2]258  rtems_shell_env_key_handle *handle;
259  handle = (rtems_shell_env_key_handle*)
260    pthread_getspecific(rtems_shell_current_env_key);
261  return handle == NULL ? NULL : handle->env;
[bb58190]262}
263
264/*
265 *  Duplication the current shell environment and if none is set
266 *  clear it.
267 */
268void rtems_shell_dup_current_env(rtems_shell_env_t *copy)
269{
270  rtems_shell_env_t *env = rtems_shell_get_current_env();
[d007cc2]271  if (env != NULL) {
272    shell_std_debug("dup: existing parent\n");
[bb58190]273    *copy = *env;
[e765cfb]274
275    /*
276     * Duplicated environments are not managed.
277     */
278    copy->managed = false;
279  } else {
[d007cc2]280    *copy = rtems_global_shell_env;
281    copy->parent_stdout = stdout;
282    copy->parent_stdin  = stdin;
283    copy->parent_stderr = stderr;
284    shell_std_debug("dup: global: copy: %p out: %d (%p) in: %d (%p)\n",
285                    copy,
286                    fileno(copy->parent_stdout), copy->parent_stdout,
287                    fileno(copy->parent_stdin), copy->parent_stdin);
[bb58190]288  }
[6cd4a5c]289}
290
[529402f5]291/*
292 *  Move a string in a buffer to the left (e.g. when a character
293 *  is deleted). The string must be NUL-terminated and the
294 *  NUL-character will be moved too.
295 */
296static void rtems_shell_move_left(char *start, size_t offset)
297{
298  memmove(start, start + offset, strlen(start + offset) + 1);
299}
300
[814d9588]301/*
302 *  Get a line of user input with modest features
303 */
[94547d1]304static int rtems_shell_line_editor(
[ea90df23]305  char       *cmds[],
306  int         count,
307  int         size,
308  const char *prompt,
309  FILE       *in,
310  FILE       *out
311)
312{
313  unsigned int extended_key;
[7c4cdeb9]314  int          c;
[ea90df23]315  int          col;
316  int          last_col;
317  char         line[size];
318  char         new_line[size];
319  int          up;
320  int          cmd = -1;
321  int          inserting = 1;
[d007cc2]322  int          in_fileno = fileno(in);
[ea90df23]323
324  col = last_col = 0;
[8a775c27]325
[d007cc2]326  tcdrain(in_fileno);
[9320c7ec]327  if (out != NULL) {
328    tcdrain(fileno(out));
329  }
[ea90df23]330
[9320c7ec]331  if (out != NULL && prompt != NULL)
[ea90df23]332    fprintf(out, "\r%s", prompt);
[8a775c27]333
[ea90df23]334  line[0] = 0;
335  new_line[0] = 0;
[8a775c27]336
[ea90df23]337  for (;;) {
[8a775c27]338
[9320c7ec]339    if (out != NULL)
[ea90df23]340      fflush(out);
341
342    extended_key = rtems_shell_getchar(in);
343
344    if (extended_key == EOF)
345      return -2;
[8a775c27]346
[ea90df23]347    c = extended_key & RTEMS_SHELL_KEYS_NORMAL_MASK;
[8a775c27]348
[ea90df23]349    /*
350     * Make the extended_key usable as a boolean.
351     */
352    extended_key &= ~RTEMS_SHELL_KEYS_NORMAL_MASK;
[8a775c27]353
[ea90df23]354    up = 0;
[8a775c27]355
[ea90df23]356    if (extended_key)
357    {
358      switch (c)
359      {
360        case RTEMS_SHELL_KEYS_END:
[9320c7ec]361          if (out != NULL)
[8bca4fc]362            fprintf(out, "%s", line + col);
[ea90df23]363          col = (int) strlen (line);
364          break;
365
366        case RTEMS_SHELL_KEYS_HOME:
[9320c7ec]367          if (out != NULL && prompt != NULL) {
368            fprintf(out,"\r%s", prompt);
[ea90df23]369          }
370          col = 0;
371          break;
372
373        case RTEMS_SHELL_KEYS_LARROW:
[22e98377]374          c = 2;
375          extended_key = 0;
[ea90df23]376          break;
377
[22e98377]378        case RTEMS_SHELL_KEYS_RARROW:
379          c = 6;
380          extended_key = 0;
381          break;
[ea90df23]382
383        case RTEMS_SHELL_KEYS_UARROW:
[22e98377]384          c = 16;
385          extended_key = 0;
386          break;
[ea90df23]387
388        case RTEMS_SHELL_KEYS_DARROW:
[22e98377]389          c = 14;
390          extended_key = 0;
391          break;
[ea90df23]392
393        case RTEMS_SHELL_KEYS_DEL:
394          if (line[col] != '\0')
395          {
396            int end;
397            int bs;
[529402f5]398            rtems_shell_move_left(line + col, 1);
[9320c7ec]399            if (out != NULL) {
[ea90df23]400              fprintf(out,"\r%s%s ", prompt, line);
401              end = (int) strlen (line);
402              for (bs = 0; bs < ((end - col) + 1); bs++)
403                fputc('\b', out);
404            }
405          }
406          break;
407
408        case RTEMS_SHELL_KEYS_INS:
409          inserting = inserting ? 0 : 1;
410          break;
411      }
412    }
[22e98377]413    if (!extended_key)
[ea90df23]414    {
415      switch (c)
416      {
[22e98377]417        case 1:                         /*Control-a*/
[9320c7ec]418          if (out != NULL && prompt != NULL) {
419            fprintf(out,"\r%s", prompt);
[ea90df23]420          }
421          col = 0;
422          break;
[8a775c27]423
[22e98377]424        case 2:                         /* Control-B */
425          if (col > 0)
426          {
427            col--;
[9320c7ec]428            if (out != NULL)
[22e98377]429              fputc('\b', out);
430          }
431          break;
432
433        case 4:                         /* Control-D */
434          if (strlen(line)) {
435            if (col < strlen(line)) {
[529402f5]436              rtems_shell_move_left(line + col, 1);
[9320c7ec]437              if (out != NULL) {
[22e98377]438                int bs;
439                fprintf(out,"%s \b", line + col);
440                for (bs = 0; bs < ((int) strlen (line) - col); bs++)
441                  fputc('\b', out);
442              }
443            }
444            break;
445          }
446          /* Fall through */
447
448        case EOF:
[9320c7ec]449          if (out != NULL)
[22e98377]450            fputc('\n', out);
451          return -2;
452
453        case 5:                         /*Control-e*/
[9320c7ec]454          if (out != NULL)
[8bca4fc]455            fprintf(out, "%s", line + col);
[ea90df23]456          col = (int) strlen (line);
457          break;
458
[22e98377]459        case 6:                         /* Control-F */
460          if ((col < size) && (line[col] != '\0')) {
[9320c7ec]461            if (out != NULL)
[22e98377]462              fputc(line[col], out);
463            col++;
464          }
465          break;
466
467        case 7:                         /* Control-G */
[9320c7ec]468          if (out != NULL) {
[06ac8b71]469            /*
470             * The (int) cast is needed because the width specifier (%*)
471             * must be an int, but strlen() returns a size_t. Without
472             * the case, the result is a printf() format warning.
473             */
474            fprintf(out,"\r%s%*c", prompt, (int) strlen (line), ' ');
[22e98377]475            fprintf(out,"\r%s\x7", prompt);
476          }
477          memset (line, '\0', strlen(line));
478          col = 0;
479          break;
480
481        case 11:                        /*Control-k*/
[ea90df23]482          if (line[col]) {
[9320c7ec]483            if (out != NULL) {
[ea90df23]484              int end = strlen(line);
485              int bs;
486              fprintf(out,"%*c", end - col, ' ');
487              for (bs = 0; bs < (end - col); bs++)
488                fputc('\b', out);
489            }
490            line[col] = '\0';
491          }
492          break;
[8a775c27]493
[ea90df23]494        case '\f':
[9320c7ec]495          if (out != NULL) {
[ea90df23]496            int end;
497            int bs;
498            fputc('\f',out);
499            fprintf(out,"\r%s%s", prompt, line);
500            end = (int) strlen (line);
501            for (bs = 0; bs < (end - col); bs++)
502              fputc('\b', out);
503          }
504          break;
505
506        case '\b':
507        case '\x7f':
508          if (col > 0)
509          {
510            int bs;
511            col--;
[529402f5]512            rtems_shell_move_left(line + col, 1);
[9320c7ec]513            if (out != NULL) {
[ea90df23]514              fprintf(out,"\b%s \b", line + col);
515              for (bs = 0; bs < ((int) strlen (line) - col); bs++)
516                fputc('\b', out);
517            }
518          }
519          break;
520
521        case '\n':
522        case '\r':
523        {
524          /*
525           * Process the command.
526           */
[9320c7ec]527          if (out != NULL)
[ea90df23]528            fprintf(out,"\n");
[8a775c27]529
[ea90df23]530          /*
531           * Only process the command if we have a command and it is not
532           * repeated in the history.
533           */
534          if (strlen(line) == 0) {
535            cmd = -1;
536          } else {
537            if ((cmd < 0) || (strcmp(line, cmds[cmd]) != 0)) {
538              if (count > 1)
539                memmove(cmds[1], cmds[0], (count - 1) * size);
540              memmove (cmds[0], line, size);
541              cmd = 0;
[22e98377]542            } else {
543              if ((cmd > 1) && (strcmp(line, cmds[cmd]) == 0)) {
544                memmove(cmds[1], cmds[0], cmd * size);
545                memmove (cmds[0], line, size);
546                cmd = 0;
547              }
[ea90df23]548            }
549          }
550        }
551        return cmd;
552
[22e98377]553        case 16:                         /* Control-P */
554          if ((cmd >= (count - 1)) || (strlen(cmds[cmd + 1]) == 0)) {
[9320c7ec]555            if (out != NULL)
[22e98377]556              fputc('\x7', out);
557            break;
558          }
559
560          up = 1;
561          /* drop through */
562
563        case 14:                        /* Control-N */
564        {
565          int last_cmd = cmd;
566          int clen = strlen (line);
567
568          if (prompt)
569            clen += strlen(prompt);
570
571          if (up) {
572            cmd++;
573          } else {
574            if (cmd < 0) {
[9320c7ec]575              if (out != NULL)
[22e98377]576                fprintf(out, "\x7");
577              break;
578            }
579            else
580              cmd--;
581          }
582
583          if ((last_cmd < 0) || (strcmp(cmds[last_cmd], line) != 0))
584            memcpy (new_line, line, size);
585
586          if (cmd < 0)
587            memcpy (line, new_line, size);
588          else
589            memcpy (line, cmds[cmd], size);
590
591          col = strlen (line);
592
[9320c7ec]593          if (out != NULL) {
[22e98377]594            fprintf(out,"\r%s%*c", prompt, clen, ' ');
595            fprintf(out,"\r%s%s", prompt, line);
596          }
597        }
598        break;
599
600        case 20:                        /* Control-T */
601          if (col > 0)
602          {
603            char tmp;
604            if (col == strlen(line)) {
605              col--;
[9320c7ec]606              if (out != NULL)
[22e98377]607                fprintf(out,"\b");
608            }
609            tmp           = line[col];
610            line[col]     = line[col - 1];
611            line[col - 1] = tmp;
[9320c7ec]612            if (out != NULL)
[22e98377]613              fprintf(out,"\b%c%c", line[col - 1], line[col]);
614            col++;
615          } else {
[9320c7ec]616            if (out != NULL)
[22e98377]617              fputc('\x7', out);
618          }
619          break;
620
621        case 21:                        /* Control-U */
622          if (col > 0)
623          {
[2361b2c]624            /* strlen() returns size_t but fprintf("%*...") below requires
625             * int! */
626            int clen = (int) strlen (line);
[ffc928b]627            int bs;
[22e98377]628
[529402f5]629            rtems_shell_move_left(line, col);
[9320c7ec]630            if (out != NULL) {
[22e98377]631              fprintf(out,"\r%s%*c", prompt, clen, ' ');
632              fprintf(out,"\r%s%s", prompt, line);
[ffc928b]633
634              for (bs = 0; bs < strlen(line); bs++) {
635                fputc('\b', out);
636              }
[22e98377]637            }
638            col = 0;
639          }
640          break;
641
[ea90df23]642        default:
[7311863]643          if ((col < (size - 1)) && (c >= ' ') && (c <= '~')) {
[ea90df23]644            int end = strlen (line);
645            if (inserting && (col < end) && (end < size)) {
646              int ch, bs;
647              for (ch = end + 1; ch > col; ch--)
648                line[ch] = line[ch - 1];
[9320c7ec]649              if (out != NULL) {
[8bca4fc]650                fprintf(out, "%s", line + col);
[ea90df23]651                for (bs = 0; bs < (end - col + 1); bs++)
652                  fputc('\b', out);
653              }
654            }
655            line[col++] = c;
656            if (col > end)
657              line[col] = '\0';
[9320c7ec]658            if (out != NULL)
[ea90df23]659              fputc(c, out);
660          }
661          break;
662      }
663    }
664  }
665  return -2;
666}
667
[fa028bb]668static bool rtems_shell_login(rtems_shell_env_t *env, FILE * in,FILE * out)
669{
[d007cc2]670  FILE  *fd;
671  int    c;
672  time_t t;
[bb58190]673
[6dd411aa]674  if (out) {
[bb58190]675    if ((env->devname[5]!='p')||
676        (env->devname[6]!='t')||
677        (env->devname[7]!='y')) {
[6dd411aa]678      fd = fopen("/etc/issue","r");
679      if (fd) {
[d007cc2]680        while ((c = fgetc(fd)) != EOF) {
[6dd411aa]681          if (c=='@')  {
[d007cc2]682            switch (c = fgetc(fd)) {
[6dd411aa]683              case 'L':
[bb58190]684                fprintf(out,"%s", env->devname);
[6dd411aa]685                break;
686              case 'B':
687                fprintf(out,"0");
688                break;
[70d689a]689              case 'T':
[6dd411aa]690              case 'D':
691                time(&t);
692                fprintf(out,"%s",ctime(&t));
693                break;
694              case 'S':
695                fprintf(out,"RTEMS");
696                break;
697              case 'V':
[1af8e45b]698                fprintf(
699                  out,
700                  "%s\n%s",
701                  rtems_get_version_string(),
702                  rtems_get_copyright_notice()
703                );
[6dd411aa]704                break;
705              case '@':
706                fprintf(out,"@");
707                break;
708              default :
709                fprintf(out,"@%c",c);
710                break;
711            }
712          } else if (c=='\\')  {
713            switch(c=fgetc(fd)) {
714              case '\\': fprintf(out,"\\"); break;
715              case 'b':  fprintf(out,"\b"); break;
716              case 'f':  fprintf(out,"\f"); break;
717              case 'n':  fprintf(out,"\n"); break;
718              case 'r':  fprintf(out,"\r"); break;
719              case 's':  fprintf(out," ");  break;
720              case 't':  fprintf(out,"\t"); break;
721              case '@':  fprintf(out,"@");  break;
722            }
723          } else {
724            fputc(c,out);
725          }
726        }
727        fclose(fd);
728      }
729    } else {
730      fd = fopen("/etc/issue.net","r");
731      if (fd) {
732        while ((c=fgetc(fd))!=EOF) {
733          if (c=='%')  {
734            switch(c=fgetc(fd)) {
735              case 't':
[bb58190]736                fprintf(out,"%s", env->devname);
[6dd411aa]737                break;
738              case 'h':
739                fprintf(out,"0");
740                break;
741              case 'D':
742                fprintf(out," ");
743                break;
744              case 'd':
745                time(&t);
746                fprintf(out,"%s",ctime(&t));
747                break;
748              case 's':
749                fprintf(out,"RTEMS");
750                break;
751              case 'm':
752                fprintf(out,"(" CPU_NAME "/" CPU_MODEL_NAME ")");
753                break;
754              case 'r':
[4b9b6dd]755                fprintf(out,rtems_get_version_string());
[6dd411aa]756                break;
757              case 'v':
[1af8e45b]758                fprintf(
759                  out,
760                  "%s\n%s",
761                  rtems_get_version_string(),
762                  rtems_get_copyright_notice()
763                );
[6dd411aa]764                break;
765              case '%':fprintf(out,"%%");
766                break;
767              default:
768                fprintf(out,"%%%c",c);
769                break;
770            }
771          } else {
772            fputc(c,out);
773          }
774        }
775        fclose(fd);
776      }
777    }
778  }
779
[bb58190]780  return rtems_shell_login_prompt(in, out, env->devname, env->login_check);
[b2712e3]781}
782
[814d9588]783#if defined(SHELL_DEBUG)
[2eeb648c]784void rtems_shell_print_env(
785  rtems_shell_env_t * shell_env
[6dd411aa]786)
787{
788  if ( !shell_env ) {
789    printk( "shell_env is NULL\n" );
[20b1bdb]790
[6dd411aa]791    return;
792  }
793  printk( "shell_env=%p\n"
794    "shell_env->magic=0x%08x\t"
795    "shell_env->devname=%s\n"
796    "shell_env->taskname=%s\t"
797    "shell_env->exit_shell=%d\t"
798    "shell_env->forever=%d\n",
799    shell_env->magic,
800    shell_env->devname,
801    ((shell_env->taskname) ? shell_env->taskname : "NOT SET"),
802    shell_env->exit_shell,
803    shell_env->forever
804  );
805}
806#endif
[dd74e612]807
[7260887]808/*
809 * Wait for the string to return or timeout.
810 */
811static bool rtems_shell_term_wait_for(const int fd, const char* str, const int timeout)
812{
813  int msec = timeout;
814  int i = 0;
815  while (msec-- > 0 && str[i] != '\0') {
816    char ch[2];
817    if (read(fd, &ch[0], 1) == 1) {
818      fflush(stdout);
819      if (ch[0] != str[i++]) {
820        return false;
821      }
822      msec = timeout;
823    } else {
824      usleep(1000);
825    }
826  }
827  if (msec == 0) {
828    return false;
829  }
830  return true;
831}
832
833/*
834 * Buffer a string up to the end string
835 */
836static int rtems_shell_term_buffer_until(const int fd,
837                                         char* buf,
838                                         const int size,
839                                         const char* end,
840                                         const int timeout)
841{
842  int msec = timeout;
843  int i = 0;
844  int e = 0;
845  memset(&buf[0], 0, size);
846  while (msec-- > 0 && i < size && end[e] != '\0') {
847    char ch[2];
848    if (read(fd, &ch[0], 1) == 1) {
849      fflush(stdout);
850      buf[i++] = ch[0];
851      if (ch[0] == end[e]) {
852        e++;
853      } else {
854        e = 0;
855      }
856      msec = timeout;
857    } else {
858      usleep(1000);
859    }
860  }
861  if (msec == 0 || end[e] != '\0') {
862    return -1;
863  }
864  i -= e;
865  if (i < size) {
866    buf[i] = '\0';
867  }
868  return i;
869}
870
871/*
872 * Determine if the terminal has the row and column values
873 * swapped
874 *
875 * https://github.com/tmux/tmux/issues/3457
876 *
877 * Tmux has a bug where the lines and cols are swapped. There is a lag
878 * in the time it takes to get the fix into code so see if tmux is
879 * running and which version and work around the bug.
880 *
881 * The terminal device needs to have VMIN=0, and VTIME=0
882 */
883static bool rtems_shell_term_row_column_swapped(const int fd, const int timeout) {
884  char buf[64];
885  memset(&buf[0], 0, sizeof(buf));
886  /*
887   * CSI > Ps q
888   *    Ps = 0   =>   DCS > | text ST
889   */
890  fputs("\033[>0q", stdout);
891  fflush(stdout);
892  if (rtems_shell_term_wait_for(fd, "\033P>|", timeout)) {
893    int len = rtems_shell_term_buffer_until(fd, buf, sizeof(buf), "\033\\", timeout);
894    if (len > 0) {
895      if (memcmp(buf, "tmux ", 5) == 0) {
896        static const char* bad_versions[] = {
897          "3.2", "3.2a", "3.3", "3.3a"
898        };
899        size_t i;
900        for (i = 0; i < RTEMS_ARRAY_SIZE(bad_versions); ++i) {
901          if (strcmp(bad_versions[i], buf + 5) == 0) {
902            return true;
903          }
904        }
905      }
906    }
907  }
908  return false;
909}
910
[8425e67]911/*
912 * Direct method to get the size of an XTERM window.
913 *
914 * If you do not use an XTERM the env variables are not define.
915 */
916static void rtems_shell_winsize( void )
917{
918  const int fd = fileno(stdin);
919  struct winsize ws;
[7260887]920  const int timeout = 150;
[8425e67]921  char buf[64];
922  bool ok = false;
923  int lines = 0;
924  int cols = 0;
925  int r;
926  r = ioctl(fd, TIOCGWINSZ, &ws);
927  if (r == 0) {
928    ok = true;
929    lines = ws.ws_row;
930    cols = ws.ws_col;
931  } else if (isatty(fd)) {
932    struct termios cterm;
933    if (tcgetattr(fd, &cterm) >= 0) {
934      struct termios term = cterm;
935      term.c_cc[VMIN] = 0;
936      term.c_cc[VTIME] = 0;
937      if (tcsetattr (fd, TCSADRAIN, &term) >= 0) {
938        memset(&buf[0], 0, sizeof(buf));
939        /*
940         * https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Miscellaneous
941         *
942         * CSI 1 8 t
943         */
944        fputs("\033[18t", stdout);
945        fflush(stdout);
[7260887]946        if (rtems_shell_term_wait_for(fd, "\033[8;", timeout)) {
947          int len = rtems_shell_term_buffer_until(fd, buf, sizeof(buf), ";", timeout);
948          if (len > 0) {
949            int i;
950            lines = 0;
951            i = 0;
952            while (i < len) {
[8425e67]953              lines *= 10;
954              lines += buf[i++] - '0';
955            }
[7260887]956            len = rtems_shell_term_buffer_until(fd, buf, sizeof(buf), "t", timeout);
957            if (len > 0) {
958              cols = 0;
959              i = 0;
960              while (i < len) {
961                cols *= 10;
962                cols += buf[i++] - '0';
963              }
964              ok = true;
[8425e67]965            }
966          }
967        }
968      }
[7260887]969      if (rtems_shell_term_row_column_swapped(fd, timeout)) {
970        int tmp = lines;
971        lines = cols;
972        cols = tmp;
973      }
[8425e67]974      tcsetattr (fd, TCSADRAIN, &cterm);
975    }
976  }
977  if (ok) {
978    snprintf(buf, sizeof(buf) - 1, "%d", lines);
979    setenv("LINES", buf, 1);
980    snprintf(buf, sizeof(buf) - 1, "%d", cols);
981    setenv("COLUMNS", buf, 1);
982  }
983}
984
[94547d1]985static rtems_task rtems_shell_task(rtems_task_argument task_argument)
[6dd411aa]986{
[1ff9922]987  rtems_shell_env_t *shell_env = (rtems_shell_env_t*) task_argument;
988  rtems_id           wake_on_end = shell_env->wake_on_end;
989  rtems_shell_main_loop( shell_env );
[20b1bdb]990  rtems_shell_clear_shell_std_handles();
[1ff9922]991  if (wake_on_end != RTEMS_INVALID_ID)
992    rtems_event_send (wake_on_end, RTEMS_EVENT_1);
[f004b2b8]993  rtems_task_exit();
[6dd411aa]994}
[dd74e612]995
[fa028bb]996static bool rtems_shell_init_user_env(void)
997{
998  rtems_status_code sc;
999
1000  /* Make sure we have a private user environment */
1001  sc = rtems_libio_set_private_env();
1002  if (sc != RTEMS_SUCCESSFUL) {
[d007cc2]1003    rtems_error(sc, "rtems_libio_set_private_env():");
[fa028bb]1004    return false;
1005  }
1006
1007  /* Make an effective root user */
1008  seteuid(0);
1009  setegid(0);
1010
1011  return chroot("/") == 0;
1012}
1013
[ea90df23]1014#define RTEMS_SHELL_MAXIMUM_ARGUMENTS (128)
1015#define RTEMS_SHELL_CMD_SIZE          (128)
1016#define RTEMS_SHELL_CMD_COUNT         (32)
1017#define RTEMS_SHELL_PROMPT_SIZE       (128)
[aed742c]1018
[1a8ad7e]1019static bool shell_main_loop(
1020  rtems_shell_env_t *shell_env,
1021  bool               interactive,
1022  FILE              *line_editor_output
[798ff5a]1023)
[6dd411aa]1024{
[1a8ad7e]1025  bool result = false;
1026  int line = 0;
1027  int cmd_count;
1028  char *cmds[RTEMS_SHELL_CMD_COUNT];
1029  char *cmd_argv;
1030  char *prompt;
1031
1032  if (interactive) {
1033    prompt = malloc(RTEMS_SHELL_PROMPT_SIZE);
1034    if (prompt == NULL) {
1035      fprintf(stderr, "shell: cannot allocate prompt memory\n");
[1167235]1036      return false;
[1ff9922]1037    }
[d007cc2]1038
[ea90df23]1039    cmd_count = RTEMS_SHELL_CMD_COUNT;
[9320c7ec]1040  } else {
[1a8ad7e]1041    prompt = NULL;
1042    cmd_count = 1;
[9320c7ec]1043  }
1044
[ea90df23]1045  /*
1046   * Allocate the command line buffers.
1047   */
[8c422e2]1048  cmd_argv = malloc (RTEMS_SHELL_CMD_SIZE);
1049  if (!cmd_argv) {
1050    fprintf(stderr, "no memory for command line buffers\n" );
1051  }
[8a775c27]1052
[ea90df23]1053  cmds[0] = calloc (cmd_count, RTEMS_SHELL_CMD_SIZE);
1054  if (!cmds[0]) {
1055    fprintf(stderr, "no memory for command line buffers\n" );
1056  }
[8c422e2]1057
1058  if (cmd_argv && cmds[0]) {
[1a8ad7e]1059    size_t cmd;
[ea90df23]1060
1061    memset (cmds[0], 0, cmd_count * RTEMS_SHELL_CMD_SIZE);
1062
1063    for (cmd = 1; cmd < cmd_count; cmd++) {
1064      cmds[cmd] = cmds[cmd - 1] + RTEMS_SHELL_CMD_SIZE;
[6dd411aa]1065    }
[8a775c27]1066
[ea90df23]1067    do {
[fa028bb]1068      result = rtems_shell_init_user_env();
1069
1070      if (result) {
1071        /*
1072         *  By using result here, we can fall to the bottom of the
1073         *  loop when the connection is dropped during login and
1074         *  keep on trucking.
1075         */
1076        if (shell_env->login_check != NULL) {
[20b1bdb]1077          result = rtems_shell_login(shell_env, stdin, stdout);
[fa028bb]1078        } else {
[ffd5285]1079          setuid(shell_env->uid);
1080          setgid(shell_env->gid);
1081          seteuid(shell_env->uid);
1082          setegid(shell_env->gid);
1083          rtems_current_user_env_getgroups();
1084
[fa028bb]1085          result = true;
1086        }
[7c4cdeb9]1087      }
1088
1089      if (result)  {
[ea90df23]1090        memset (cmds[0], 0, cmd_count * RTEMS_SHELL_CMD_SIZE);
[1a8ad7e]1091
1092        if (interactive) {
[ea90df23]1093          rtems_shell_cat_file(stdout,"/etc/motd");
1094          fprintf(stdout, "\n"
[a2097c5]1095                  "RTEMS Shell on %s. Use 'help' to list commands.\n",
[ea90df23]1096                  shell_env->devname);
[55c64fc9]1097          chdir("/"); /* XXX: chdir to getpwent homedir */
[1a8ad7e]1098        } else {
1099          chdir(shell_env->cwd);
1100        }
[8a775c27]1101
[1167235]1102        shell_env->exit_shell = false;
[ea90df23]1103
1104        for (;;) {
[1a8ad7e]1105          const char *c;
1106          int argc;
1107          char *argv[RTEMS_SHELL_MAXIMUM_ARGUMENTS];
1108
[ea90df23]1109          /* Prompt section */
1110          if (prompt) {
1111            rtems_shell_get_prompt(shell_env, prompt,
1112                                   RTEMS_SHELL_PROMPT_SIZE);
1113          }
[8a775c27]1114
[ea90df23]1115          /* getcmd section */
1116          cmd = rtems_shell_line_editor(cmds, cmd_count,
1117                                        RTEMS_SHELL_CMD_SIZE, prompt,
[9320c7ec]1118                                        stdin, line_editor_output);
[ea90df23]1119
1120          if (cmd == -1)
1121            continue; /* empty line */
[8a775c27]1122
[d007cc2]1123          if (cmd == -2) {
1124            result = false;
[ea90df23]1125            break; /*EOF*/
[d007cc2]1126          }
[ea90df23]1127
1128          line++;
1129
[55c64fc9]1130          if (shell_env->echo)
1131            fprintf(stdout, "%d: %s\n", line, cmds[cmd]);
[8a775c27]1132
[ea90df23]1133          /* evaluate cmd section */
1134          c = cmds[cmd];
1135          while (*c) {
[bab5c5fa]1136            if (!isblank((unsigned char)*c))
[ea90df23]1137              break;
1138            c++;
1139          }
[1ff9922]1140
[ea90df23]1141          if (*c == '\0')   /* empty line */
1142            continue;
[a5de1ef]1143
[ea90df23]1144          if (*c == '#') {  /* comment character */
1145            cmds[cmd][0] = 0;
1146            continue;
1147          }
[1ff9922]1148
[ea90df23]1149          if (!strcmp(cmds[cmd],"bye") || !strcmp(cmds[cmd],"exit")) {
1150            fprintf(stdout, "Shell exiting\n" );
1151            break;
1152          }
[6dd411aa]1153
[ea90df23]1154          /* exec cmd section */
1155          /* TODO:
1156           *  To avoid user crash catch the signals.
1157           *  Open a new stdio files with posibility of redirection *
1158           *  Run in a new shell task background. (unix &)
1159           *  Resuming. A little bash.
1160           */
[8c422e2]1161          memcpy (cmd_argv, cmds[cmd], RTEMS_SHELL_CMD_SIZE);
1162          if (!rtems_shell_make_args(cmd_argv, &argc, argv,
[ea90df23]1163                                     RTEMS_SHELL_MAXIMUM_ARGUMENTS)) {
[8425e67]1164            int exit_code;
1165            rtems_shell_winsize();
1166            exit_code = rtems_shell_execute_cmd(argv[0], argc, argv);
[d007cc2]1167            if (shell_env->exit_code != NULL)
1168              *shell_env->exit_code = exit_code;
1169            if (exit_code != 0 && shell_env->exit_on_error)
1170              shell_env->exit_shell = true;
[6dd411aa]1171          }
[ea90df23]1172
1173          /* end exec cmd section */
1174          if (shell_env->exit_shell)
1175            break;
[6dd411aa]1176        }
1177
[ea90df23]1178        fflush( stdout );
1179        fflush( stderr );
[6dd411aa]1180      }
[d007cc2]1181      shell_std_debug("end: %d %d\n", result, shell_env->forever);
[ea90df23]1182    } while (result && shell_env->forever);
[1a8ad7e]1183  }
1184
1185  free(cmds[0]);
1186  free(cmd_argv);
1187  free(prompt);
1188
1189  return result;
1190}
1191
[2342625]1192bool rtems_shell_run_main_loop(
1193  rtems_shell_env_t *shell_env,
1194  bool               interactive,
1195  FILE              *line_editor_output
1196)
1197{
1198  bool result;
1199
1200  if (shell_env->magic != SHELL_MAGIC) {
1201    return false;
1202  }
1203
1204  if (!rtems_shell_init_user_env()) {
1205    return false;
1206  }
1207
1208  if (!rtems_shell_set_shell_env(shell_env)) {
1209    return false;
1210  }
1211
1212  result = shell_main_loop(shell_env, interactive, line_editor_output);
1213  rtems_shell_clear_shell_env();
1214  return result;
1215}
1216
[1a8ad7e]1217bool rtems_shell_main_loop(
1218  rtems_shell_env_t *shell_env
1219)
1220{
1221  struct termios  term;
1222  struct termios  previous_term;
1223  bool            result;
1224  bool            interactive = true;
1225  FILE           *stdinToClose = NULL;
1226  FILE           *stdoutToClose = NULL;
1227  FILE           *line_editor_output;
1228
[3407a3b]1229  if (shell_env->magic != SHELL_MAGIC) {
[1a8ad7e]1230    rtems_error(0, "invalid shell environment passed to the main loop)");
1231    return false;
1232  }
1233
1234  if (!rtems_shell_set_shell_env(shell_env))
1235    return false;
1236
1237  if (!rtems_shell_init_user_env()) {
1238    rtems_error(0, "rtems_shell_init_user_env");
1239    rtems_shell_clear_shell_env();
1240    return false;
1241  }
1242
1243  shell_std_debug("env: %p\n", shell_env);
1244
1245  if (shell_env->output == NULL || strcmp(shell_env->output, "stdout") == 0) {
1246    if (shell_env->parent_stdout != NULL)
1247      stdout = shell_env->parent_stdout;
1248  }
1249  else if (strcmp(shell_env->output, "stderr") == 0) {
1250    if (shell_env->parent_stderr != NULL)
1251      stdout = shell_env->parent_stderr;
1252    else
1253      stdout = stderr;
1254  } else if (strcmp(shell_env->output, "/dev/null") == 0) {
1255    if (stdout == NULL) {
1256      fprintf(stderr, "shell: stdout is NULLs\n");
1257      rtems_shell_clear_shell_env();
1258      return false;
1259    }
1260    fclose (stdout);
1261  } else {
1262    FILE *output = fopen(shell_env->output,
1263                         shell_env->output_append ? "a" : "w");
1264    if (output == NULL) {
1265      fprintf(stderr, "shell: open output %s failed: %s\n",
1266              shell_env->output, strerror(errno));
1267      rtems_shell_clear_shell_env();
1268      return false;
1269    }
1270    stdout = output;
1271    stdoutToClose = output;
1272  }
[ea90df23]1273
[1a8ad7e]1274  if (shell_env->input == NULL || strcmp(shell_env->input, "stdin") == 0) {
1275    if (shell_env->parent_stdin != NULL)
1276      stdin = shell_env->parent_stdin;
1277  } else {
1278    FILE *input = fopen(shell_env->input, "r");
1279    if (input == NULL) {
1280      fprintf(stderr, "shell: open input %s failed: %s\n",
1281              shell_env->input, strerror(errno));
1282      if (stdoutToClose != NULL)
1283        fclose(stdoutToClose);
1284      rtems_shell_clear_shell_env();
1285      return false;
1286    }
1287    stdin = input;
1288    stdinToClose = input;
1289    shell_env->forever = false;
1290    interactive = false;
[ea90df23]1291  }
1292
[1a8ad7e]1293  if (interactive) {
1294    if (stdin == NULL) {
1295      fprintf(stderr, "shell: stdin is NULLs\n");
1296      if (stdoutToClose != NULL)
1297        fclose(stdoutToClose);
1298      rtems_shell_clear_shell_env();
1299      return false;
1300    }
1301    /* Make a raw terminal, Linux Manuals */
1302    if (tcgetattr(fileno(stdin), &previous_term) >= 0) {
1303      term = previous_term;
1304      term.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
1305      term.c_oflag &= ~OPOST;
1306      term.c_oflag |= (OPOST|ONLCR); /* But with cr+nl on output */
1307      term.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
1308      term.c_cflag |= CLOCAL | CREAD;
1309      term.c_cc[VMIN]  = 1;
1310      term.c_cc[VTIME] = 0;
1311      if (tcsetattr (fileno(stdin), TCSADRAIN, &term) < 0) {
1312        fprintf(stderr,
1313                "shell: cannot set terminal attributes(%s)\n",shell_env->devname);
1314      }
1315    }
1316  }
1317
1318  shell_std_debug("child out: %d (%p)\n", fileno(stdout), stdout);
1319  shell_std_debug("child  in: %d (%p)\n", fileno(stdin), stdin);
1320
1321   /* Do not buffer if interactive else leave buffered */
1322  if (interactive)
1323    setvbuf(stdin, NULL, _IONBF, 0);
1324  setvbuf(stdout, NULL, _IONBF, 0);
1325
1326  if (isatty(fileno(stdin))) {
1327     line_editor_output = stdout;
1328  } else {
1329     line_editor_output = NULL;
1330  }
[798ff5a]1331
[1a8ad7e]1332  result = shell_main_loop(shell_env, interactive, line_editor_output);
[d007cc2]1333  shell_std_debug("child in-to-close: %p\n", stdinToClose);
1334  shell_std_debug("child out-to-close: %p\n", stdoutToClose);
1335
[8084ce80]1336  if (stdinToClose) {
[a3ddb08b]1337    fclose( stdinToClose );
[8084ce80]1338  } else {
[798ff5a]1339    if (tcsetattr(fileno(stdin), TCSADRAIN, &previous_term) < 0) {
[8084ce80]1340      fprintf(
1341        stderr,
1342        "shell: cannot reset terminal attributes (%s)\n",
1343        shell_env->devname
1344      );
1345    }
1346  }
[a3ddb08b]1347  if ( stdoutToClose )
1348    fclose( stdoutToClose );
[d007cc2]1349  rtems_shell_clear_shell_env();
[1ff9922]1350  return result;
[dd74e612]1351}
[6dd411aa]1352
[dd74e612]1353/* ----------------------------------------------- */
[cbd1e87]1354static rtems_status_code rtems_shell_run (
1355  const char *task_name,
1356  size_t task_stacksize,
1357  rtems_task_priority task_priority,
1358  const char *devname,
1359  bool forever,
1360  bool wait,
1361  const char *input,
1362  const char *output,
1363  bool output_append,
1364  rtems_id wake_on_end,
1365  bool echo,
1366  rtems_shell_login_check_t login_check
[6dd411aa]1367)
1368{
1369  rtems_id           task_id;
1370  rtems_status_code  sc;
[2eeb648c]1371  rtems_shell_env_t *shell_env;
[4e5299f]1372  rtems_name         name;
1373
[d007cc2]1374  rtems_shell_init_environment();
1375
[e41eaa88]1376  if ( task_name && strlen(task_name) >= 4)
[814d9588]1377    name = rtems_build_name(
1378      task_name[0], task_name[1], task_name[2], task_name[3]);
[4e5299f]1379  else
[3407a3b]1380    name = SHELL_MAGIC;
[6dd411aa]1381
1382  sc = rtems_task_create(
[4e5299f]1383    name,
[6dd411aa]1384    task_priority,
[4e5299f]1385    task_stacksize,
[3899a537]1386    RTEMS_PREEMPT | RTEMS_TIMESLICE | RTEMS_NO_ASR,
[6dd411aa]1387    RTEMS_LOCAL | RTEMS_FLOATING_POINT,
1388    &task_id
1389  );
1390  if (sc != RTEMS_SUCCESSFUL) {
[d007cc2]1391    rtems_error(sc,"creating task %s in shell_init()",task_name);
[6dd411aa]1392    return sc;
1393  }
1394
[2eeb648c]1395  shell_env = rtems_shell_init_env( NULL );
[6dd411aa]1396  if ( !shell_env )  {
[d007cc2]1397   rtems_error(RTEMS_NO_MEMORY,
1398               "allocating shell_env %s in shell_init()",task_name);
[6dd411aa]1399   return RTEMS_NO_MEMORY;
1400  }
[d007cc2]1401
1402  shell_std_debug("run: env: %p\n", shell_env);
1403
[1ff9922]1404  shell_env->devname       = devname;
1405  shell_env->taskname      = task_name;
[d007cc2]1406
[1167235]1407  shell_env->exit_shell    = false;
[1ff9922]1408  shell_env->forever       = forever;
[55c64fc9]1409  shell_env->echo          = echo;
[d007cc2]1410  shell_env->input         = input == NULL ? NULL : strdup (input);
1411  shell_env->output        = output == NULL ? NULL : strdup (output);
[1ff9922]1412  shell_env->output_append = output_append;
[d007cc2]1413  shell_env->parent_stdin  = stdin;
1414  shell_env->parent_stdout = stdout;
1415  shell_env->parent_stderr = stderr;
[1ff9922]1416  shell_env->wake_on_end   = wake_on_end;
[8a775c27]1417  shell_env->login_check   = login_check;
[ffd5285]1418  shell_env->uid           = getuid();
1419  shell_env->gid           = getgid();
[6dd411aa]1420
[55c64fc9]1421  getcwd(shell_env->cwd, sizeof(shell_env->cwd));
1422
[d007cc2]1423  shell_std_debug("run out: %d (%p)\n",
1424                  fileno(shell_env->parent_stdout), shell_env->parent_stdout);
1425  shell_std_debug("run  in: %d (%p)\n",
1426                  fileno(shell_env->parent_stdin), shell_env->parent_stdin);
1427
[798ff5a]1428  sc = rtems_task_start(task_id, rtems_shell_task,
[d007cc2]1429                        (rtems_task_argument) shell_env);
[798ff5a]1430  if (sc != RTEMS_SUCCESSFUL) {
[d007cc2]1431    rtems_error(sc,"starting task %s in shell_init()",task_name);
1432    free( (void*) shell_env->input );
1433    free( (void*) shell_env->output );
1434    free( shell_env );
[798ff5a]1435    return sc;
1436  }
1437
1438  if (wait) {
1439    rtems_event_set out;
1440    sc = rtems_event_receive (RTEMS_EVENT_1, RTEMS_WAIT, 0, &out);
1441  }
1442
[b837c83]1443  shell_std_debug("run: end: sc:%d\n", sc);
[d007cc2]1444
1445  return sc;
[6dd411aa]1446}
[1ff9922]1447
[798ff5a]1448rtems_status_code rtems_shell_init(
[cbd1e87]1449  const char *task_name,
1450  size_t task_stacksize,
1451  rtems_task_priority task_priority,
1452  const char *devname,
1453  bool forever,
1454  bool wait,
1455  rtems_shell_login_check_t login_check
[1ff9922]1456)
1457{
[06f8e558]1458  rtems_id to_wake = RTEMS_ID_NONE;
[798ff5a]1459
1460  if ( wait )
1461    to_wake = rtems_task_self();
1462
1463  return rtems_shell_run(
1464    task_name,               /* task_name */
1465    task_stacksize,          /* task_stacksize */
1466    task_priority,           /* task_priority */
1467    devname,                 /* devname */
1468    forever,                 /* forever */
1469    wait,                    /* wait */
1470    "stdin",                 /* input */
1471    "stdout",                /* output */
[06f8e558]1472    false,                   /* output_append */
[798ff5a]1473    to_wake,                 /* wake_on_end */
[06f8e558]1474    false,                   /* echo */
[8a775c27]1475    login_check              /* login check */
[798ff5a]1476  );
[1ff9922]1477}
1478
[d007cc2]1479rtems_status_code rtems_shell_script (
[e41eaa88]1480  const char          *task_name,
[06f8e558]1481  size_t               task_stacksize,
[1ff9922]1482  rtems_task_priority  task_priority,
1483  const char*          input,
1484  const char*          output,
[06f8e558]1485  bool                 output_append,
1486  bool                 wait,
1487  bool                 echo
[1ff9922]1488)
1489{
[d007cc2]1490  rtems_id to_wake = RTEMS_ID_NONE;
[1ff9922]1491  rtems_status_code sc;
1492
[d007cc2]1493  shell_std_debug("script: in: %s out: %s\n", input, output);
1494
1495  if ( wait )
1496    to_wake = rtems_task_self();
[8a775c27]1497
[798ff5a]1498  sc = rtems_shell_run(
1499    task_name,       /* task_name */
1500    task_stacksize,  /* task_stacksize */
1501    task_priority,   /* task_priority */
1502    NULL,            /* devname */
1503    0,               /* forever */
1504    wait,            /* wait */
1505    input,           /* input */
1506    output,          /* output */
1507    output_append,   /* output_append */
[d007cc2]1508    to_wake,         /* wake_on_end */
[06f8e558]1509    echo,            /* echo */
[8a775c27]1510    NULL             /* login check */
[798ff5a]1511  );
[d007cc2]1512
1513  if (sc == RTEMS_SUCCESSFUL)
1514  {
1515    /* Place holder until RTEMS 5 is released then the interface for
1516     * this call will change. */
1517  }
1518
1519  shell_std_debug("script: end: %d\n", sc);
[1ff9922]1520
1521  return sc;
1522}
Note: See TracBrowser for help on using the repository browser.