source: rtems/cpukit/libmisc/shell/shell.c @ 8084ce80

4.104.114.95
Last change on this file since 8084ce80 was 8084ce80, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on 07/10/08 at 06:04:19

Restore terminal settings on exit.

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