source: rtems/cpukit/libmisc/shell/shell.c @ 798ff5a

4.104.114.95
Last change on this file since 798ff5a was 798ff5a, checked in by Joel Sherrill <joel.sherrill@…>, on 07/16/08 at 17:17:29

2008-07-16 Joel Sherrill <joel.sherrill@…>

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