summaryrefslogtreecommitdiffstats
path: root/c/src
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>2001-04-20 20:35:45 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>2001-04-20 20:35:45 +0000
commitdd74e612f1ffe208ad1e20f28ac4da3f08764879 (patch)
tree52d3f65d7197ccbe922d6c2e5b211da8be2ec552 /c/src
parent2001-04-20 Radzislaw Galler <rgaller@et.put.poznan.pl> (diff)
downloadrtems-dd74e612f1ffe208ad1e20f28ac4da3f08764879.tar.bz2
2001-04-20 Correo Fernando-ruiz <correo@fernando-ruiz.com>
* Added initial shell functionality. * Makefile.am, configure.in, wrapup/Makefile.am: * shell/.cvsignore, shell/Makefile.am, shell/README, shell/cmds.c, shell/shell.c, shell/shell.h: New files.
Diffstat (limited to 'c/src')
-rw-r--r--c/src/libmisc/ChangeLog6
-rw-r--r--c/src/libmisc/Makefile.am2
-rw-r--r--c/src/libmisc/configure.in1
-rw-r--r--c/src/libmisc/shell/.cvsignore2
-rw-r--r--c/src/libmisc/shell/Makefile.am44
-rw-r--r--c/src/libmisc/shell/README28
-rw-r--r--c/src/libmisc/shell/cmds.c479
-rw-r--r--c/src/libmisc/shell/shell.c470
-rw-r--r--c/src/libmisc/shell/shell.h72
-rw-r--r--c/src/libmisc/wrapup/Makefile.am1
10 files changed, 1104 insertions, 1 deletions
diff --git a/c/src/libmisc/ChangeLog b/c/src/libmisc/ChangeLog
index ad0a3f6f6c..03d1878f57 100644
--- a/c/src/libmisc/ChangeLog
+++ b/c/src/libmisc/ChangeLog
@@ -1,3 +1,9 @@
+2001-04-20 Correo Fernando-ruiz <correo@fernando-ruiz.com>
+
+ * Added initial shell functionality.
+ * Makefile.am, configure.in, wrapup/Makefile.am:
+ * shell/.cvsignore, shell/Makefile.am, shell/README,
+ shell/cmds.c, shell/shell.c, shell/shell.h: New files.
2001-04-20 Joel Sherrill <joel@OARcorp.com>
* devnull/devnull.c (null_initialize): Added check to
diff --git a/c/src/libmisc/Makefile.am b/c/src/libmisc/Makefile.am
index 0474afc71a..39f14528ea 100644
--- a/c/src/libmisc/Makefile.am
+++ b/c/src/libmisc/Makefile.am
@@ -5,7 +5,7 @@
AUTOMAKE_OPTIONS = foreign 1.4
ACLOCAL_AMFLAGS = -I ../../../aclocal
-SUBDIRS = devnull dummy dumpbuf stackchk monitor cpuuse rtmonuse untar \
+SUBDIRS = devnull dummy dumpbuf stackchk monitor cpuuse shell rtmonuse untar \
mw-fb wrapup
EXTRA_DIST = README
diff --git a/c/src/libmisc/configure.in b/c/src/libmisc/configure.in
index 28628bb222..664485b1d4 100644
--- a/c/src/libmisc/configure.in
+++ b/c/src/libmisc/configure.in
@@ -33,6 +33,7 @@ AM_CONDITIONAL(HAS_MP,test "$HAS_MP" = "yes")
AC_OUTPUT(
Makefile
cpuuse/Makefile
+shell/Makefile
devnull/Makefile
dummy/Makefile
dumpbuf/Makefile
diff --git a/c/src/libmisc/shell/.cvsignore b/c/src/libmisc/shell/.cvsignore
new file mode 100644
index 0000000000..282522db03
--- /dev/null
+++ b/c/src/libmisc/shell/.cvsignore
@@ -0,0 +1,2 @@
+Makefile
+Makefile.in
diff --git a/c/src/libmisc/shell/Makefile.am b/c/src/libmisc/shell/Makefile.am
new file mode 100644
index 0000000000..814cf40c44
--- /dev/null
+++ b/c/src/libmisc/shell/Makefile.am
@@ -0,0 +1,44 @@
+##
+## $Id$
+##
+
+AUTOMAKE_OPTIONS = foreign 1.4
+
+include_rtemsdir = $(includedir)/rtems
+
+LIBNAME = libshell-tmp
+LIB = $(ARCH)/$(LIBNAME).a
+
+C_FILES = cmds.c shell.c
+C_O_FILES = $(C_FILES:%.c=$(ARCH)/%.o)
+
+include_rtems_HEADERS = shell.h
+
+OBJS = $(C_O_FILES)
+
+include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
+include $(top_srcdir)/../../../automake/compile.am
+include $(top_srcdir)/../../../automake/lib.am
+
+$(PROJECT_INCLUDE)/rtems:
+ @$(mkinstalldirs) $@
+$(PROJECT_INCLUDE)/rtems/%.h: %.h
+ $(INSTALL_DATA) $< $@
+
+#
+# (OPTIONAL) Add local stuff here using +=
+#
+
+$(LIB): $(OBJS)
+ $(make-library)
+
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems \
+ $(include_rtems_HEADERS:%=$(PROJECT_INCLUDE)/rtems/%)
+
+all-local: $(ARCH) $(PREINSTALL_FILES) $(OBJS) $(LIB)
+
+.PRECIOUS: $(LIB)
+
+EXTRA_DIST = README shell.c cmds.c shell.h
+
+include $(top_srcdir)/../../../automake/local.am
diff --git a/c/src/libmisc/shell/README b/c/src/libmisc/shell/README
new file mode 100644
index 0000000000..2d38451cc6
--- /dev/null
+++ b/c/src/libmisc/shell/README
@@ -0,0 +1,28 @@
+#
+# $Id$
+#
+
+This directory contains a shell user extension
+primary features:
+
+ + create a user shell terminal task.
+
+This code has not been extensively tested. It is provided as a tool
+for RTEMS users to open more shell terminal.
+Suggestions and comments are appreciated.
+
+NOTES:
+
+1. printf() & getchar() works but you can't use
+ 0,1,2 like fildes. You need to use fileno(stdin),fileno(stdout),...
+
+2. You only need a termios dev to start a new session, add your new commands
+ and enjoy it.
+
+
+
+FUTURE:
+
+1. Adding new commands in cmds.c to give file manegement to shell.
+
+2. Create a telnetd daemon. (pseudo-terminal needed)
diff --git a/c/src/libmisc/shell/cmds.c b/c/src/libmisc/shell/cmds.c
new file mode 100644
index 0000000000..52a4079bf2
--- /dev/null
+++ b/c/src/libmisc/shell/cmds.c
@@ -0,0 +1,479 @@
+/*
+ * Author: Fernando RUIZ CASAS
+ *
+ * Work: fernando.ruiz@ctv.es
+ * Home: correo@fernando-ruiz.com
+ *
+ * This file is inspired in rtems_monitor & Chris John MyRightBoot
+ *
+ * But I want to make it more user friendly
+ * A 'monitor' command is added to adapt the call rtems monitor commands
+ * at my call procedure
+ *
+ * MINIX date.c is adapted to run here. Like a exercise only....
+ *
+ * TODO: A lot of improvements of course.
+ * cat, cp, rm, mv, ...
+ * hexdump,
+ *
+ * More? Say me it, please...
+ *
+ * The BSP Specific are not welcome here.
+ *
+ * C&S welcome...
+ *
+ * $Id$
+ */
+
+#undef __STRICT_ANSI__ /* fileno() */
+#include <stdio.h>
+#include <termios.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <stddef.h>
+
+#include <rtems.h>
+#include <rtems/monitor.h>
+#include <rtems/score/tod.h>
+
+#include <imfs.h>
+#include <rtems/shell.h>
+
+/* ----------------------------------------------- *
+ - str to int "0xaffe" "0b010010" "0123" "192939"
+ * ----------------------------------------------- */
+int str2int(char * s) {
+ int sign=1;
+ int base=10;
+ int value=0;
+ int digit;
+ if (!s) return 0;
+ if (*s) {
+ if (*s=='-') {
+ sign=-1;
+ s++;
+ if (!*s) return 0;
+ };
+ if (*s=='0') {
+ s++;
+ switch(*s) {
+ case 'x':
+ case 'X':s++;
+ base=16;
+ break;
+ case 'b':
+ case 'B':s++;
+ base=2;
+ break;
+ default :base=8;
+ break;
+ }
+ };
+ while (*s) {
+ switch(*s) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':digit=*s-'0';
+ break;
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':digit=*s-'A'+10;
+ break;
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':digit=*s-'a'+10;
+ break;
+ default:return value*sign;
+ };
+ if (digit>base) return value*sign;
+ value=value*base+digit;
+ s++;
+ };
+ };
+ return value*sign;
+}
+/*----------------------------------------------------------------------------*
+ * RAM MEMORY COMMANDS
+ *----------------------------------------------------------------------------*/
+
+#define mdump_adr (current_shell_env->mdump_adr) /* static value */
+
+int main_mdump(int argc,char * argv[]) {
+ unsigned char n,m,max=0;
+ int adr=mdump_adr;
+ unsigned char * pb;
+ if (argc>1) adr=str2int(argv[1]);
+ if (argc>2) max=str2int(argv[2]);
+ max/=16;
+ if (!max) max=20;
+ for (m=0;m<max;m++) {
+ printf("0x%08X ",adr);
+ pb=(unsigned char*) adr;
+ for (n=0;n<16;n++)
+ printf("%02X%c",pb[n],n==7?'-':' ');
+ for (n=0;n<16;n++) {
+ printf("%c",isprint(pb[n])?pb[n]:'.');
+ };
+ printf("\n");
+ adr+=16;
+ };
+ mdump_adr=adr;
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+int main_mwdump(int argc,char * argv[]) {
+ unsigned char n,m,max=0;
+ int adr=mdump_adr;
+ unsigned short * pw;
+ if (argc>1) adr=str2int(argv[1]);
+ if (argc>2) max=str2int(argv[2]);
+ max/=16;
+ if (!max) max=20;
+ for (m=0;m<max;m++) {
+ printf("0x%08X ",adr);
+ pw=(unsigned short*) adr;
+ for (n=0;n<8;n++)
+ printf("%02X %02X%c",pw[n]/0x100,pw[n]%0x100,n==3?'-':' ');
+ for (n=0;n<8;n++) {
+ printf("%c",isprint(pw[n]/0x100)?pw[n]/0x100:'.');
+ printf("%c",isprint(pw[n]%0x100)?pw[n]%0x100:'.');
+ };
+ printf("\n");
+ adr+=16;
+ };
+ mdump_adr=adr;
+ return 0;
+}
+/*----------------------------------------------------------------------------*/
+int main_medit(int argc,char * argv[]) {
+ unsigned char * pb;
+ int n,i;
+ if (argc<3) {
+ printf("too few arguments\n");
+ return 0;
+ };
+ pb=(unsigned char*)str2int(argv[1]);
+ i=2;
+ n=0;
+ while (i<=argc) {
+ pb[n++]=str2int(argv[i++])%0x100;
+ }
+ mdump_adr=(int)pb;
+ return main_mdump(0,NULL);
+}
+/*----------------------------------------------------------------------------*/
+int main_mfill(int argc,char * argv[]) {
+ int adr;
+ int size;
+ unsigned char value;
+ if (argc<4) {
+ printf("too few arguments\n");
+ return 0;
+ };
+ adr =str2int(argv[1]);
+ size =str2int(argv[2]);
+ value=str2int(argv[3])%0x100;
+ memset((unsigned char*)adr,size,value);
+ mdump_adr=adr;
+ return main_mdump(0,NULL);
+}
+/*----------------------------------------------------------------------------*/
+int main_mmove(int argc,char * argv[]) {
+ int src;
+ int dst;
+ int size;
+ if (argc<4) {
+ printf("too few arguments\n");
+ return 0;
+ };
+ dst =str2int(argv[1]);
+ src =str2int(argv[2]);
+ size =str2int(argv[3]);
+ memcpy((unsigned char*)dst,(unsigned char*)src,size);
+ mdump_adr=dst;
+ return main_mdump(0,NULL);
+}
+/*----------------------------------------------------------------------------*/
+#ifdef MALLOC_STATS /* /rtems/s/src/lib/libc/malloc.c */
+int main_malloc_dump(int argc,char * argv[]) {
+ void malloc_dump(void);
+ malloc_dump();
+ return 0;
+}
+#endif
+/*----------------------------------------------------------------------------
+ * Reset. Assumes that the watchdog is present.
+ *----------------------------------------------------------------------------*/
+int main_reset (int argc, char **argv)
+{
+ rtems_interrupt_level level;
+ printf ("Waiting for watchdog ... ");
+ tcdrain(fileno(stdout));
+
+ rtems_interrupt_disable (level);
+ for (;;)
+ ;
+ return 0;
+}
+/*----------------------------------------------------------------------------
+ * Alias. make an alias
+ *----------------------------------------------------------------------------*/
+int main_alias (int argc, char **argv)
+{
+ if (argc<3) {
+ printf("too few arguments\n");
+ return 1;
+ };
+ if (!shell_alias_cmd(argv[1],argv[2])) {
+ printf("unable to make an alias(%s,%s)\n",argv[1],argv[2]);
+ };
+ return 0;
+}
+/*-----------------------------------------------------------*
+ * Directory commands
+ *-----------------------------------------------------------*/
+int main_ls(int argc, char *argv[])
+{
+ char * fname;
+ DIR *dirp;
+ struct dirent *dp;
+ struct stat stat_buf;
+ char sbuf[256];
+ char nbuf[1024];
+ int n,size;
+
+ fname=".";
+ if (argc>1) fname=argv[1];
+
+ if ((dirp = opendir(fname)) == NULL)
+ {
+ printf("%s: No such file or directory.\n", fname);
+ return errno;
+ }
+ n=0;
+ size=0;
+ while ((dp = readdir(dirp)) != NULL)
+ {
+ strcpy(nbuf,fname);
+ if (nbuf[strlen(nbuf)-1]!='/') strcat(nbuf,"/");
+ strcat(nbuf,dp->d_name); /* always the fullpathname. Avoid ftpd problem.*/
+ if (stat(nbuf, &stat_buf) == 0)
+ { /* AWFUL buts works...*/
+ strftime(sbuf,sizeof(sbuf)-1,"%b %d %H:%M",gmtime(&stat_buf.st_atime));
+ printf("%c%c%c%c%c%c%c%c%c%c %3d rtems rtems %11d %s %s%c\n",
+ (S_ISLNK(stat_buf.st_mode)?('l'):
+ (S_ISDIR(stat_buf.st_mode)?('d'):('-'))),
+ (stat_buf.st_mode & S_IRUSR)?('r'):('-'),
+ (stat_buf.st_mode & S_IWUSR)?('w'):('-'),
+ (stat_buf.st_mode & S_IXUSR)?('x'):('-'),
+ (stat_buf.st_mode & S_IRGRP)?('r'):('-'),
+ (stat_buf.st_mode & S_IWGRP)?('w'):('-'),
+ (stat_buf.st_mode & S_IXGRP)?('x'):('-'),
+ (stat_buf.st_mode & S_IROTH)?('r'):('-'),
+ (stat_buf.st_mode & S_IWOTH)?('w'):('-'),
+ (stat_buf.st_mode & S_IXOTH)?('x'):('-'),
+ (int)stat_buf.st_nlink,
+ (int)stat_buf.st_size,
+ sbuf,
+ dp->d_name,
+ S_ISDIR(stat_buf.st_mode)?'/':' ');
+ n++;
+ size+=stat_buf.st_size;
+ }
+ }
+ printf("%d files %d bytes occupied\n",n,size);
+ closedir(dirp);
+ return 0;
+}
+/*-----------------------------------------------------------*/
+int main_pwd (int argc, char *argv[]) {
+ char dir[1024];
+ getcwd(dir,1024);
+ printf("%s\n",dir);
+ return 0;
+}
+/*-----------------------------------------------------------*/
+int main_chdir (int argc, char *argv[]) {
+ char *dir;
+ dir="/";
+ if (argc>1) dir=argv[1];
+ if (chdir(dir)) {
+ printf("chdir to '%s' failed:%s\n",dir,strerror(errno));
+ return errno;
+ };
+ return 0;
+}
+/*-----------------------------------------------------------*/
+int main_mkdir (int argc, char *argv[]) {
+ char *dir;
+ dir=NULL;
+ if (argc>1) dir=argv[1];
+ if (mkdir(dir,S_IRWXU|S_IRWXG|S_IRWXO)) {
+ printf("mkdir '%s' failed:%s\n",dir,strerror(errno));
+ };
+ return errno;
+}
+/*-----------------------------------------------------------*/
+int main_rmdir (int argc, char *argv[])
+{
+ char *dir;
+ dir=NULL;
+ if (argc>1) dir=argv[1];
+ if (rmdir(dir)) printf("rmdir '%s' failed:%s\n",dir,strerror(errno));
+ return errno;
+}
+/*-----------------------------------------------------------*/
+int main_chroot(int argc,char * argv[]) {
+ char * new_root="/";
+ if (argc==2) new_root=argv[1];
+ if (chroot(new_root)<0) {
+ printf("error %s:chroot(%s);\n",strerror(errno),new_root);
+ return -1;
+ };
+ return 0;
+}
+/*-----------------------------------------------------------*/
+/* date - print or set time and date Author: Jan Looyen */
+/* MINIX 1.5 GPL'ed */
+
+
+#define MIN 60L /* # seconds in a minute */
+#define HOUR (60 * MIN) /* # seconds in an hour */
+#define DAY (24 * HOUR) /* # seconds in a day */
+#define YEAR (365 * DAY) /* # seconds in a year */
+
+static int conv(unsigned32 *value,char **ptr,unsigned32 max)
+{
+ int buf;
+ *ptr -= 2;
+ buf = atoi(*ptr);
+ **ptr = 0;
+ if (buf < 0 || buf > max) {
+ fprintf(stderr, "Date: bad conversion\n");
+ return 0;
+ };
+ *value=buf;
+ return 1;
+}
+
+static int set_time(char *t)
+{
+ rtems_time_of_day tod;
+ FILE * rtc;
+ char *tp;
+ int len;
+ if (rtems_clock_get(RTEMS_CLOCK_GET_TOD,&tod)!=RTEMS_SUCCESSFUL)
+ memset(&tod,0,sizeof(tod));
+ len = strlen(t);
+ if (len != 12 && len != 10 && len != 6 && len != 4) return 0;
+ tp = t;
+ while (*tp)
+ if (!isdigit(*tp++)) {
+ fprintf(stderr, "date: bad conversion\n");
+ return 0;
+ };
+ if (len == 6 || len == 12)
+ if (!conv(&tod.second,&tp, 59)) return 0;
+ if (!conv(&tod.minute,&tp, 59)) return 0;
+ if (!conv(&tod.hour,&tp, 23)) return 0;
+ if (len == 12 || len == 10) {
+ if (!conv(&tod.year,&tp, 99)) return 0;
+ tod.year+=1900;
+ if (tod.year<TOD_BASE_YEAR) tod.year+=100;
+ if (!conv(&tod.day ,&tp, 31)) return 0;
+ if (!conv(&tod.month ,&tp, 12)) return 0;
+ }
+ if (!_TOD_Validate(&tod)) {
+ fprintf(stderr, "Invalid date value\n");
+ } else {
+ rtems_clock_set(&tod);
+ rtems_clock_get(RTEMS_CLOCK_GET_TOD,&tod);
+ rtc=fopen("/dev/rtc","r+");
+ if (rtc) {
+ fwrite(&tod,sizeof(tod),1,rtc);
+ fclose(rtc);
+ };
+ };
+ return 1;
+}
+
+int main_date(int argc,char *argv[])
+{
+ time_t t;
+ if (argc == 2) set_time(argv[1]);
+ time(&t);
+ printf("%s", ctime(&t));
+ return 0;
+}
+/*-----------------------------------------------------------*
+ * with this you can call at all the rtems monitor commands.
+ * Not all work fine but you can show the rtems status and more.
+ *-----------------------------------------------------------*/
+int main_monitor(int argc,char * argv[]) {
+ rtems_monitor_command_entry_t *command;
+ extern rtems_monitor_command_entry_t rtems_monitor_commands[];
+ rtems_task_ident(RTEMS_SELF,0,&rtems_monitor_task_id);
+ rtems_monitor_node = rtems_get_node(rtems_monitor_task_id);
+ rtems_monitor_default_node = rtems_monitor_node;
+ if ((command=rtems_monitor_command_lookup(rtems_monitor_commands,argc,argv)))
+ command->command_function(argc, argv, command->command_arg, 0);
+ return 0;
+}
+/*-----------------------------------------------------------*/
+void register_cmds(void) {
+ rtems_monitor_command_entry_t *command;
+ extern rtems_monitor_command_entry_t rtems_monitor_commands[];
+ /* dir[ectories] topic */
+ shell_add_cmd ("ls" ,"dir","ls [dir] # list files in the directory" ,main_ls );
+ shell_add_cmd ("chdir" ,"dir","chdir [dir] # change the current directory",main_chdir);
+ shell_add_cmd ("rmdir" ,"dir","rmdir dir # remove directory" ,main_rmdir);
+ shell_add_cmd ("mkdir" ,"dir","mkdir dir # make a directory" ,main_mkdir);
+ shell_add_cmd ("pwd" ,"dir","pwd # print work directory" ,main_pwd );
+ shell_add_cmd ("chroot","dir","chroot [dir] # change the root directory" ,main_chroot);
+
+ shell_alias_cmd("ls" ,"dir");
+ shell_alias_cmd("chdir" ,"cd");
+
+ /* misc. topic */
+ shell_add_cmd ("date" ,"misc","date [[MMDDYY]hhmm[ss]]" ,main_date);
+ shell_add_cmd ("reset","misc","reset the BSP" ,main_reset);
+ shell_add_cmd ("alias","misc","alias old new" ,main_alias);
+
+ /* memory topic */
+ shell_add_cmd ("mdump","mem" ,"mdump [adr [size]]" ,main_mdump);
+ shell_add_cmd ("wdump","mem" ,"wdump [adr [size]]" ,main_mwdump);
+ shell_add_cmd ("medit","mem" ,"medit adr value [value ...]" ,main_medit);
+ shell_add_cmd ("mfill","mem" ,"mfill adr size value" ,main_mfill);
+ shell_add_cmd ("mmove","mem" ,"mmove dst src size" ,main_mmove);
+#ifdef MALLOC_STATS /* /rtems/s/src/lib/libc/malloc.c */
+ shell_add_cmd ("malloc","mem","mem show memory malloc'ed" ,main_mem);
+#endif
+ /* monitor topic */
+ command=rtems_monitor_commands;
+ while (command) {
+ shell_add_cmd(command->command,"monitor",
+ command->usage ,main_monitor);
+ command=command->next;
+ };
+}
+/*-----------------------------------------------------------*/
diff --git a/c/src/libmisc/shell/shell.c b/c/src/libmisc/shell/shell.c
new file mode 100644
index 0000000000..d7c2502d90
--- /dev/null
+++ b/c/src/libmisc/shell/shell.c
@@ -0,0 +1,470 @@
+/*
+ *
+ * Instantatiate a new terminal shell.
+ *
+ * Author:
+ *
+ * WORK: fernando.ruiz@ctv.es
+ * HOME: correo@fernando-ruiz.com
+ *
+ * Thanks at:
+ * Chris John
+ *
+ * $Id$
+ */
+
+#undef __STRICT_ANSI__ /* fileno() */
+#include <stdio.h>
+
+#include <rtems.h>
+#include <rtems/error.h>
+#include <rtems/libio.h>
+#include <rtems/libio_.h>
+
+#include <termios.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <rtems/shell.h>
+/* ----------------------------------------------- *
+ * This is a stupidity but is cute.
+ * ----------------------------------------------- */
+rtems_unsigned32 new_rtems_name(char * rtems_name) {
+ static char b[5];
+ sprintf(b,"%-4.4s",rtems_name);
+ return rtems_build_name(b[0],b[1],b[2],b[3]);
+}
+/* **************************************************************
+ * common linked list of shell commands.
+ * Because the help report is very long
+ * I have a topic for each command.
+ * Help list the topics
+ * help [topic] list the commands for the topic
+ * help [command] help for the command
+ * Can you see help rtems monitor report?
+ * ************************************************************** */
+
+struct shell_topic_tt;
+typedef struct shell_topic_tt shell_topic_t;
+
+struct shell_topic_tt {
+ char * topic;
+ shell_topic_t * next;
+};
+
+
+static shell_cmd_t * shell_first_cmd;
+static shell_topic_t * shell_first_topic;
+/* ----------------------------------------------- *
+ * Using Chain I can reuse the rtems code.
+ * I am more comfortable with this, sorry.
+ * ----------------------------------------------- */
+shell_topic_t * shell_lookup_topic(char * topic) {
+ shell_topic_t * shell_topic;
+ shell_topic=shell_first_topic;
+ while (shell_topic) {
+ if (!strcmp(shell_topic->topic,topic)) return shell_topic;
+ shell_topic=shell_topic->next;
+ };
+ return (shell_topic_t *) NULL;
+}
+/* ----------------------------------------------- */
+shell_topic_t * shell_add_topic(char * topic) {
+ shell_topic_t * current,*aux;
+ if (!shell_first_topic) {
+ aux=malloc(sizeof(shell_topic_t));
+ aux->topic=topic;
+ aux->next=(shell_topic_t*)NULL;
+ return shell_first_topic=aux;
+ } else {
+ current=shell_first_topic;
+ if (!strcmp(topic,current->topic)) return current;
+ while (current->next) {
+ if (!strcmp(topic,current->next->topic)) return current->next;
+ current=current->next;
+ };
+ aux=malloc(sizeof(shell_topic_t));
+ aux->topic=topic;
+ aux->next=(shell_topic_t*)NULL;
+ current->next=aux;
+ return aux;
+ };
+}
+/* ----------------------------------------------- */
+shell_cmd_t * shell_lookup_cmd(char * cmd) {
+ shell_cmd_t * shell_cmd;
+ shell_cmd=shell_first_cmd;
+ while (shell_cmd) {
+ if (!strcmp(shell_cmd->name,cmd)) return shell_cmd;
+ shell_cmd=shell_cmd->next;
+ };
+ return (shell_cmd_t *) NULL;
+}
+/* ----------------------------------------------- */
+shell_cmd_t * shell_add_cmd(char * cmd,
+ char * topic,
+ char * usage,
+ shell_command_t command) {
+ int shell_help(int argc,char * argv[]);
+ shell_cmd_t * shell_cmd,*shell_pvt;
+ if (!shell_first_cmd) {
+ shell_first_cmd=(shell_cmd_t *) malloc(sizeof(shell_cmd_t));
+ shell_first_cmd->name ="help";
+ shell_first_cmd->topic ="help";
+ shell_first_cmd->usage ="help [topic] # list of usage of commands";
+ shell_first_cmd->command=shell_help;
+ shell_first_cmd->alias =(shell_cmd_t *) NULL;
+ shell_first_cmd->next =(shell_cmd_t *) NULL;
+ shell_add_topic(shell_first_cmd->topic);
+ register_cmds();
+ };
+ if (!cmd) return (shell_cmd_t *) NULL;
+ if (!command) return (shell_cmd_t *) NULL;
+ shell_cmd=(shell_cmd_t *) malloc(sizeof(shell_cmd_t));
+ shell_cmd->name =cmd;
+ shell_cmd->topic =topic;
+ shell_cmd->usage =usage;
+ shell_cmd->command=command;
+ shell_cmd->alias =(shell_cmd_t *) NULL;
+ shell_cmd->next =(shell_cmd_t *) NULL;
+ shell_add_topic(shell_cmd->topic);
+ shell_pvt=shell_first_cmd;
+ while (shell_pvt->next) shell_pvt=shell_pvt->next;
+ return shell_pvt->next=shell_cmd;
+}
+/* ----------------------------------------------- *
+ * you can make an alias for every command.
+ * ----------------------------------------------- */
+shell_cmd_t * shell_alias_cmd(char * cmd, char * alias) {
+ shell_cmd_t * shell_cmd,* shell_aux;
+ shell_aux=(shell_cmd_t *) NULL;
+ if (alias) {
+ if ((shell_aux=shell_lookup_cmd(alias))!=NULL) {
+ return NULL;
+ };
+ if ((shell_cmd=shell_lookup_cmd(cmd))!=NULL) {
+ shell_aux=shell_add_cmd(alias,shell_cmd->topic,
+ shell_cmd->usage,shell_cmd->command);
+ if (shell_aux) shell_aux->alias=shell_cmd;
+ };
+ };
+ return shell_aux;
+}
+/* ----------------------------------------------- *
+ * Poor but enough..
+ * TODO: Redirection capture. "" evaluate, ... C&S welcome.
+ * ----------------------------------------------- */
+int shell_make_args(char * cmd,
+ int * pargc,
+ char * argv[]) {
+ int argc=0;
+ while ((cmd=strtok(cmd," \t\r\n"))!=NULL) {
+ argv[argc++]=cmd;
+ cmd=(char*)NULL;
+ };
+ argv[argc]=(char*)NULL;
+ return *pargc=argc;
+}
+/* ----------------------------------------------- *
+ * show the help for one command.
+ * ----------------------------------------------- */
+int shell_help_cmd(shell_cmd_t * shell_cmd) {
+ char * pc;
+ int col,line;
+ printf("%-10.10s -",shell_cmd->name);
+ col=12;
+ line=1;
+ if (shell_cmd->alias) {
+ printf("is an <alias> for command '%s'",shell_cmd->alias->name);
+ } else
+ if (shell_cmd->usage) {
+ pc=shell_cmd->usage;
+ while (*pc) {
+ switch(*pc) {
+ case '\r':break;
+ case '\n':putchar('\n');
+ col=0;
+ break;
+ default :putchar(*pc);
+ col++;
+ break;
+ };
+ pc++;
+ if(col>78) { /* What daring... 78?*/
+ if (*pc) {
+ putchar('\n');
+ col=0;
+ };
+ };
+ if (!col && *pc) {
+ printf(" ");
+ col=12;line++;
+ };
+ };
+ };
+ puts("");
+ return line;
+}
+/* ----------------------------------------------- *
+ * show the help. The first command implemented.
+ * Can you see the header of routine? Known?
+ * The same with all the commands....
+ * ----------------------------------------------- */
+int shell_help(int argc,char * argv[]) {
+ int col,line,arg;
+ shell_topic_t *topic;
+ shell_cmd_t * shell_cmd=shell_first_cmd;
+ if (argc<2) {
+ printf("help: TOPIC? The topics are\n");
+ topic=shell_first_topic;
+ col=0;
+ while (topic) {
+ if (!col){
+ col=printf(" %s",topic->topic);
+ } else {
+ if ((col+strlen(topic->topic)+2)>78){
+ printf("\n");
+ col=printf(" %s",topic->topic);
+ } else {
+ col+=printf(", %s",topic->topic);
+ };
+ };
+ topic=topic->next;
+ };
+ printf("\n");
+ return 1;
+ };
+ line=0;
+ for (arg=1;arg<argc;arg++) {
+ if (line>16) {
+ printf("Press any key to continue...");getchar();
+ printf("\n");
+ line=0;
+ };
+ topic=shell_lookup_topic(argv[arg]);
+ if (!topic){
+ if ((shell_cmd=shell_lookup_cmd(argv[arg]))==NULL) {
+ printf("help: topic or cmd '%s' not found. Try <help> alone for a list\n",argv[arg]);
+ line++;
+ } else {
+ line+=shell_help_cmd(shell_cmd);
+ }
+ continue;
+ };
+ printf("help: list for the topic '%s'\n",argv[arg]);
+ line++;
+ while (shell_cmd) {
+ if (!strcmp(topic->topic,shell_cmd->topic))
+ line+=shell_help_cmd(shell_cmd);
+ if (line>16) {
+ printf("Press any key to continue...");getchar();
+ printf("\n");
+ line=0;
+ };
+ shell_cmd=shell_cmd->next;
+ };
+ };
+ puts("");
+ return 0;
+}
+/* ----------------------------------------------- *
+ * TODO:Change to bash readline() better.
+ * ----------------------------------------------- */
+int shell_scanline(char * line,int size,FILE * in,FILE * out) {
+ int c,col;
+ col=0;
+ for (;;) {
+ line[col]=0;
+ c=fgetc(in);
+ switch (c) {
+ case EOF :return 0;
+ case '\r':if (out) fputc('\n',out);
+ return 1;
+ case '\b':if (col) {
+ if (out) {
+ fputc('\b',out);
+ fputc(' ',out);
+ fputc('\b',out);
+ };
+ col--;
+ } else {
+ if (out) fputc('\a',out);
+ };
+ break;
+ default :if (!iscntrl(c)) {
+ if (col<size-1) {
+ line[col++]=c;
+ if (out) fputc(c,out);
+ } else {
+ if (out) fputc('\a',out);
+ };
+ } else {
+ if (out) fputc('\a',out);
+ };
+ break;
+ };
+ };
+}
+/* ----------------------------------------------- *
+ * - The shell TASK
+ * Poor but enough..
+ * TODO: Redirection. Tty Signals. ENVVARs. Shell language.
+ * ----------------------------------------------- */
+shell_env_t global_shell_env ,
+ * current_shell_env=&global_shell_env;
+
+extern char **environ;
+
+rtems_task shell_shell(rtems_task_argument task_argument) {
+
+ shell_env_t * shell_env =(shell_env_t*) task_argument;
+ shell_cmd_t * shell_cmd;
+
+ rtems_status_code sc;
+
+ struct termios term;
+ char * devname;
+ char * curdir;
+
+ char cmd[256];
+ char last_cmd[256]; /* to repeat 'r' */
+ int argc;
+ char * argv[128];
+
+ sc=rtems_libio_set_private_env();
+ if (sc!=RTEMS_SUCCESSFUL) {
+ rtems_error(sc,"rtems_libio_set_private_env():");
+ printk("rtems_libio_set_private_env():%d",sc);
+ rtems_task_delete(RTEMS_SELF);
+ };
+
+ sc=rtems_task_variable_add(RTEMS_SELF,(void*)&current_shell_env,free);
+ if (sc!=RTEMS_SUCCESSFUL) {
+ rtems_error(sc,"rtems_task_variable_add():");
+ printk("rtems_task_variable_add():%d",sc);
+ rtems_task_delete(RTEMS_SELF);
+ };
+
+ current_shell_env=shell_env; /* Set the task var */
+
+ devname=shell_env->devname;
+
+ stdin =fopen(devname,"r+");
+
+ if (!stdin) {
+ fprintf(stderr,"shell:unable to open stdin.%s:%s\n",devname,strerror(errno));
+ printk("shell:unable to open stdin.(%s)",strerror(errno));
+ rtems_task_delete(RTEMS_SELF);
+ };
+ setvbuf(stdin,NULL,_IONBF,0); /* Not buffered*/
+ /* make a raw terminal,Linux MANuals */
+ if (tcgetattr (fileno(stdin), &term)>=0) {
+ term.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
+ term.c_oflag &= ~OPOST;
+ term.c_oflag |= (OPOST|ONLCR);
+ term.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
+ term.c_cflag = CLOCAL | CREAD |(shell_env->tcflag);
+ term.c_cc[VMIN] = 1;
+ term.c_cc[VTIME] = 0;
+ if (tcsetattr (fileno(stdin), TCSADRAIN, &term) < 0) {
+ fprintf(stderr,"shell:cannot set terminal attributes(%s)\n",devname);
+ };
+ stdout=fopen(devname,"r+");
+ if (!stdout) {
+ fprintf(stderr,"shell:unable to open stdout.%s:%s\n",devname,strerror(errno));
+ };
+ stderr=fopen(devname,"r+");
+ if (!stderr) {
+ printf("shell:unable to open stderr.%s:%s\n",devname,strerror(errno));
+ };
+ /* when the future user environment runs ok
+ * a freopen() reopens the terminals. Now this don't work
+ * (sorry but you can't use because FILENO_STDIN!=0. Better fileno(stdin))
+ */
+ };
+ shell_add_cmd(NULL,NULL,NULL,NULL); /* init the chain list*/
+ strcpy(cmd,"");
+ printf("\n"
+ "RTEMS-SHELL:%s. "__DATE__". 'help' to list commands.\n",devname);
+ curdir=malloc(1024);
+ chdir("/");
+ for (;;) {
+ /* Prompt section */
+ /* XXX: show_prompt user adjustable */
+ getcwd(curdir,1024);
+ printf("%s [%s] # ",devname,curdir);
+ /* getcmd section */
+ if (!shell_scanline(cmd,sizeof(cmd),stdin,stdout)) {
+ printf("shell:unable scanline(%s)\n",devname);
+ break;
+ };
+ /* evaluate cmd section */
+ if (!strcmp(cmd,"r")) { /* repeat last command, forced, not automatic */
+ strcpy(cmd,last_cmd);
+ } else
+ if (strcmp(cmd,"")) { /* only for get a new prompt */
+ strcpy(last_cmd,cmd);
+ };
+ /* exec cmd section */
+ /* TODO:
+ * To avoid user crash catch the signals.
+ * Open a new stdio files with posibility of redirection *
+ * Run in a new shell task background. (unix &)
+ * Resuming. A little bash.
+ */
+ if (shell_make_args(cmd,&argc,argv)) {
+ if ((shell_cmd=shell_lookup_cmd(argv[0]))!=NULL) {
+ current_shell_env->errorlevel=shell_cmd->command(argc,argv);
+ } else {
+ printf("shell:%s command not found\n",argv[0]);
+ current_shell_env->errorlevel=-1;
+ };
+ };
+ /* end exec cmd section */
+ };
+ free(curdir);
+ rtems_task_delete(RTEMS_SELF);
+}
+/* ----------------------------------------------- */
+rtems_status_code shell_init (char * task_name,
+ rtems_unsigned32 task_stacksize,
+ rtems_task_priority task_priority,
+ char * devname,
+ tcflag_t tcflag) {
+ rtems_id task_id;
+ rtems_status_code sc;
+ shell_env_t * shell_env;
+ sc=rtems_task_create(new_rtems_name(task_name),
+ task_priority,
+ task_stacksize?task_stacksize:RTEMS_MINIMUM_STACK_SIZE,
+ (RTEMS_DEFAULT_MODES&~RTEMS_ASR_MASK)|RTEMS_ASR,
+ RTEMS_DEFAULT_ATTRIBUTES,
+ &task_id);
+ if (sc!=RTEMS_SUCCESSFUL) {
+ rtems_error(sc,"creating task %s in shell_init()",task_name);
+ return sc;
+ };
+ shell_env=malloc(sizeof(shell_env_t));
+ if (!shell_env) {
+ rtems_task_delete(task_id);
+ sc=RTEMS_NO_MEMORY;
+ rtems_error(sc,"allocating shell_env %s in shell_init()",task_name);
+ return sc;
+ };
+ if (global_shell_env.magic!=new_rtems_name("SENV")) {
+ global_shell_env.magic =new_rtems_name("SENV");
+ global_shell_env.devname ="/dev/console";
+ global_shell_env.taskname="GLOBAL";
+ global_shell_env.tcflag =0;
+ };
+ shell_env->magic =global_shell_env.magic;
+ shell_env->devname =devname;
+ shell_env->taskname=task_name;
+ shell_env->tcflag =tcflag;
+ return rtems_task_start(task_id,shell_shell,(rtems_task_argument) shell_env);
+}
+/* ----------------------------------------------- */
+
diff --git a/c/src/libmisc/shell/shell.h b/c/src/libmisc/shell/shell.h
new file mode 100644
index 0000000000..89c70506c4
--- /dev/null
+++ b/c/src/libmisc/shell/shell.h
@@ -0,0 +1,72 @@
+/*
+ * $Id$
+ */
+
+#ifndef __SHELL_H__
+#define __SHELL_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rtems.h>
+#include <stdio.h>
+#include <termios.h>
+
+typedef int (*shell_command_t)(int argc,char * argv[]);
+
+struct shell_cmd_tt ;
+typedef struct shell_cmd_tt shell_cmd_t;
+
+struct shell_cmd_tt {
+ char * name;
+ char * usage;
+ char * topic;
+ shell_command_t command;
+ shell_cmd_t * alias;
+ shell_cmd_t * next;
+};
+
+rtems_unsigned32 new_rtems_name(char * rtems_name);
+shell_cmd_t * shell_lookup_cmd(char * cmd);
+shell_cmd_t * shell_add_cmd(char * cmd,
+ char * topic,
+ char * usage,
+ shell_command_t command);
+shell_cmd_t * shell_alias_cmd(char * cmd, char * alias);
+
+int shell_make_args(char * cmd,
+ int * pargc,
+ char * argv[]);
+
+typedef struct {
+ rtems_name magic; /* 'S','E','N','V': Shell Environment */
+ char * devname;
+ char * taskname;
+ tcflag_t tcflag;
+ /* user extensions */
+ int errorlevel;
+ int mdump_adr;
+} shell_env_t;
+
+int shell_scanline(char * line,int size,FILE * in,FILE * out) ;
+
+rtems_status_code shell_init(char * task_name ,
+ rtems_unsigned32 task_stacksize,/*0 default*/
+ rtems_task_priority task_priority ,
+ char * devname ,
+ tcflag_t tcflag );
+
+extern shell_env_t global_shell_env,
+ * current_shell_env;
+/*--------*/
+/* cmds.c */
+/*--------*/
+int str2int(char * s);
+void register_cmds(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/libmisc/wrapup/Makefile.am b/c/src/libmisc/wrapup/Makefile.am
index 50ca35b059..ed6b42b9fc 100644
--- a/c/src/libmisc/wrapup/Makefile.am
+++ b/c/src/libmisc/wrapup/Makefile.am
@@ -14,6 +14,7 @@ include $(top_srcdir)/../../../automake/lib.am
TMP_LIBS = ../monitor/$(ARCH)/libmonitor-tmp.a \
../untar/$(ARCH)/libuntar-tmp.a ../stackchk/$(ARCH)/libstackchk-tmp.a \
../cpuuse/$(ARCH)/libcpuuse-tmp.a ../rtmonuse/$(ARCH)/librtmonuse-tmp.a \
+ ../shell/$(ARCH)/libshell-tmp.a \
../dumpbuf/$(ARCH)/libdumpbuf-tmp.a ../devnull/$(ARCH)/libdevnull-tmp.a \
../mw-fb/$(ARCH)/libmw-fb-tmp.a