source: rtems/cpukit/libmisc/shell/shell.c @ 06f8e558

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