Index: c/src/libmisc/ChangeLog
===================================================================
--- c/src/libmisc/ChangeLog	(revision e565720aadd79ad42f8bac7a5d9aab1a7ad2e5a7)
+++ c/src/libmisc/ChangeLog	(revision b2712e35b948d7ab37cf6ef46bcdfea678506444)
@@ -1,2 +1,23 @@
+2000-05-24	Fernando Ruiz Casas <fernando.ruiz@ctv.es>
+
+	* monitor/mon-prmisc.c: Correct print line.
+	* shell/Makefile.am: Added new file telnetd.c.
+	* shell/telnetd.c, shell/telnetd.h, shell/pty.c: New files.
+	* shell/shell.c, shell/cmds.c, shell/shell.h: Numerous improvments:
+	   - The shell_init has a new parameter 'forever' because in
+	     /dev/console you need that this process runs forever but in
+	     tcp/ip not. (respawn?)
+	   - A new task for every session opened trought tcp/ip telnet client.
+	     (the chargen,daytime and more are possible of implementation but
+	     I ask me if they are necesary)
+	   - Exit from the session delete the task and when the client fails too.
+	   - More cmds have been implemented. (very reduced version of these)
+	     umask, chmod, id, whoami, rm, cat, ...
+	   - A reduced line edit has been implemented.
+	       Ctrl-C abort the input,
+	       Ctrl-d in the first position gives EOF (logout).
+	       '\b' and DEL makes the rubout operation.
+	       I think that readline() for every session spents a lot of resources.
+
 2001-04-28	Ralf Corsepius <corsepiu@faw.uni-ulm.de>
 
Index: c/src/libmisc/monitor/mon-prmisc.c
===================================================================
--- c/src/libmisc/monitor/mon-prmisc.c	(revision e565720aadd79ad42f8bac7a5d9aab1a7ad2e5a7)
+++ c/src/libmisc/monitor/mon-prmisc.c	(revision b2712e35b948d7ab37cf6ef46bcdfea678506444)
@@ -109,6 +109,6 @@
         length += rtems_monitor_dump_char(u.c[i]);
 #else
-    for (i=sizeof(u.c)-1; i ; i--)
-        length += rtems_monitor_dump_char(u.c[i]);
+    for (i=0; i<sizeof(u.c); i++)
+        length += rtems_monitor_dump_char(u.c[sizeof(u.c)-1-i]);
 #endif
     return length;
Index: c/src/libmisc/shell/Makefile.am
===================================================================
--- c/src/libmisc/shell/Makefile.am	(revision e565720aadd79ad42f8bac7a5d9aab1a7ad2e5a7)
+++ c/src/libmisc/shell/Makefile.am	(revision b2712e35b948d7ab37cf6ef46bcdfea678506444)
@@ -10,8 +10,8 @@
 LIB = $(ARCH)/$(LIBNAME).a
 
-C_FILES = cmds.c shell.c
+C_FILES = cmds.c shell.c pty.c telnetd.c
 C_O_FILES = $(C_FILES:%.c=$(ARCH)/%.o)
 
-include_rtems_HEADERS = shell.h
+include_rtems_HEADERS = shell.h telnetd.h
 
 OBJS = $(C_O_FILES)
@@ -40,5 +40,5 @@
 .PRECIOUS: $(LIB)
 
-EXTRA_DIST = README shell.c cmds.c shell.h
+EXTRA_DIST = README shell.c cmds.c pty.c telnetd.c shell.h telnetd.h
 
 include $(top_srcdir)/../../../automake/local.am
Index: c/src/libmisc/shell/README
===================================================================
--- c/src/libmisc/shell/README	(revision e565720aadd79ad42f8bac7a5d9aab1a7ad2e5a7)
+++ c/src/libmisc/shell/README	(revision b2712e35b948d7ab37cf6ef46bcdfea678506444)
@@ -20,9 +20,11 @@
     and enjoy it.
 
-
+3.  If you have tcp/ip inited you can start telnetd daemon.
+    You need register pseudo-terminals driver into device drivers table.
+    16 ptyX termios device terminales are created into /dev/.
+    Calling rtems_initialize_telnetd() starts the daemon.
+    Enjoy it.
 
 FUTURE:
 
 1.  Adding new commands in cmds.c to give file manegement to shell.
-
-2.  Create a telnetd daemon. (pseudo-terminal needed)
Index: c/src/libmisc/shell/cmds.c
===================================================================
--- c/src/libmisc/shell/cmds.c	(revision e565720aadd79ad42f8bac7a5d9aab1a7ad2e5a7)
+++ c/src/libmisc/shell/cmds.c	(revision b2712e35b948d7ab37cf6ef46bcdfea678506444)
@@ -14,5 +14,5 @@
  *
  * TODO: A lot of improvements of course. 
- *      cat, cp, rm, mv, ...
+ *      cp, mv, ...
  *      hexdump,
  *      
@@ -35,4 +35,6 @@
 #include <fcntl.h>
 #include <unistd.h>
+#include <pwd.h>
+#include <grp.h>
 #include <errno.h>
 #include <sys/types.h>
@@ -258,4 +260,8 @@
    struct dirent       *dp;
    struct stat         stat_buf;
+   struct passwd     * pwd;
+   struct group      * grp;
+   char * user;
+   char * group;
    char   sbuf[256];
    char   nbuf[1024];
@@ -280,5 +286,9 @@
       { /* 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",
+	 pwd=getpwuid(stat_buf.st_uid);
+	 user=pwd?pwd->pw_name:"nouser";
+	 grp=getgrgid(stat_buf.st_gid);
+	 group=grp?grp->gr_name:"nogrp";
+         printf("%c%c%c%c%c%c%c%c%c%c %3d %6.6s %6.6s %11d %s %s%c\n",
                  (S_ISLNK(stat_buf.st_mode)?('l'):
                     (S_ISDIR(stat_buf.st_mode)?('d'):('-'))),
@@ -293,4 +303,5 @@
                  (stat_buf.st_mode & S_IXOTH)?('x'):('-'),
                  (int)stat_buf.st_nlink,
+	 	 user,group, 
                  (int)stat_buf.st_size,
 		 sbuf,
@@ -351,4 +362,26 @@
  };
  return 0;
+}
+/*-----------------------------------------------------------*/  	
+int main_cat   (int argc, char *argv[])
+{
+   int n;
+   n=1;
+   while (n<argc) cat_file(stdout,argv[n++]);
+   return 0;
+}
+/*-----------------------------------------------------------*/  	
+int main_rm    (int argc, char *argv[])
+{
+   int n;
+   n=1;
+   while (n<argc) {
+    if (unlink(argv[n])) {
+     printf("error %s:rm %s\n",strerror(errno),argv[n]);
+     return -1;
+    };
+    n++;
+   };
+   return 0;
 }
 /*-----------------------------------------------------------*/  	
@@ -425,4 +458,65 @@
   return 0;
 }
+/*-----------------------------------------------------------*/
+int main_logoff(int argc,char *argv[]) 
+{
+  printf("logoff from the system...");	
+  current_shell_env->exit_shell=TRUE;	
+  return 0;
+}
+/*-----------------------------------------------------------*/
+int main_tty   (int argc,char *argv[]) 
+{
+  printf("%s\n",ttyname(fileno(stdin)));
+  return 0;
+}
+/*-----------------------------------------------------------*/
+int main_whoami(int argc,char *argv[]) 
+{
+   struct passwd     * pwd;
+   pwd=getpwuid(getuid());
+   printf("%s\n",pwd?pwd->pw_name:"nobody");
+   return 0;
+}
+/*-----------------------------------------------------------*/
+int main_id    (int argc,char *argv[]) 
+{
+   struct passwd     * pwd;
+   struct group      * grp;
+   pwd=getpwuid(getuid());
+   grp=getgrgid(getgid());
+   printf("uid=%d(%s),gid=%d(%s),",
+		   getuid(),pwd?pwd->pw_name:"",
+		   getgid(),grp?grp->gr_name:"");
+   pwd=getpwuid(geteuid());
+   grp=getgrgid(getegid());
+   printf("euid=%d(%s),egid=%d(%s)\n",
+		   geteuid(),pwd?pwd->pw_name:"",
+		   getegid(),grp?grp->gr_name:"");
+   return 0;
+}
+/*-----------------------------------------------------------*/
+int main_umask(int argc,char *argv[]) 
+{
+   mode_t msk=umask(0);
+   if (argc == 2) msk=str2int(argv[1]);
+   umask(msk);
+   msk=umask(0);
+   printf("0%o\n",msk);
+   umask(msk);
+   return 0;
+}
+/*-----------------------------------------------------------*/
+int main_chmod(int argc,char *argv[]) 
+{
+   int n;
+   mode_t mode;
+   if (argc > 2){
+    mode=str2int(argv[1])&0777;
+    n=2;
+    while (n<argc) chmod(argv[n++],mode);
+   };
+   return 0;
+}
 /*-----------------------------------------------------------*  	
  * with this you can call at all the rtems monitor commands.
@@ -443,4 +537,12 @@
   rtems_monitor_command_entry_t *command;
   extern rtems_monitor_command_entry_t rtems_monitor_commands[];
+  /* monitor topic */
+  command=rtems_monitor_commands;
+  while (command) {
+   if (strcmp("exit",command->command)) /*Exclude EXIT (alias quit)*/
+    shell_add_cmd(command->command,"monitor",
+                  command->usage  ,main_monitor);
+   command=command->next;
+  };
   /* dir[ectories] topic */
   shell_add_cmd  ("ls"    ,"dir","ls [dir]     # list files in the directory" ,main_ls   );
@@ -450,4 +552,7 @@
   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_add_cmd  ("cat"   ,"dir","cat n1 [n2 [n3...]]# show the ascii contents",main_cat );
+  shell_add_cmd  ("rm"    ,"dir","rm n1 [n2 [n3...]]# remove files"           ,main_rm   );
+  shell_add_cmd  ("chmod" ,"dir","chmod 0777 n1 n2... #change filemode"       ,main_chmod);
 
   shell_alias_cmd("ls"    ,"dir");
@@ -455,7 +560,14 @@
 
   /* misc. topic */
+  shell_add_cmd  ("logoff","misc","logoff from the system"                    ,main_logoff);
+  shell_alias_cmd("logoff","exit"); 
   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);
+  shell_add_cmd  ("tty"  ,"misc","show ttyname"                               ,main_tty  );
+  shell_add_cmd  ("whoami","misc","show current user"                         ,main_whoami);
+  shell_add_cmd  ("id"    ,"misc","show uid,gid,euid,egid"                    ,main_id    );
+  shell_add_cmd  ("umask" ,"misc","umask [new_umask]"                         ,main_umask );
+
 
   /* memory topic */
@@ -468,11 +580,4 @@
   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;
-  };
-}
-/*-----------------------------------------------------------*/  	
+}
+/*-----------------------------------------------------------*/  	
Index: c/src/libmisc/shell/pty.c
===================================================================
--- c/src/libmisc/shell/pty.c	(revision b2712e35b948d7ab37cf6ef46bcdfea678506444)
+++ c/src/libmisc/shell/pty.c	(revision b2712e35b948d7ab37cf6ef46bcdfea678506444)
@@ -0,0 +1,406 @@
+/*
+ * /dev/ptyXX  (A first version for pseudo-terminals)
+ *
+ *  Author: Fernando RUIZ CASAS (fernando.ruiz@ctv.es)
+ *  May 2001
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * 
+ *  $Id$
+ */
+/*-----------------------------------------*/
+#include <termios.h>
+#include <rtems.h>
+#include <rtems/libio.h>
+#include <bsp.h>
+/*-----------------------------------------*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+/*-----------------------------------------*/
+#define IAC_ESC    255
+#define IAC_DONT   254
+#define IAC_DO     253
+#define IAC_WONT   252
+#define IAC_WILL   251
+#define IAC_SB     250
+#define IAC_GA     249
+#define IAC_EL     248
+#define IAC_EC     247
+#define IAC_AYT    246
+#define IAC_AO     245
+#define IAC_IP     244
+#define IAC_BRK    243
+#define IAC_DMARK  242
+#define IAC_NOP    241
+#define IAC_SE     240
+#define IAC_EOR    239
+
+struct pty_tt;
+typedef struct pty_tt pty_t;
+
+struct pty_tt {
+ char                     *devname;
+ struct rtems_termios_tty *ttyp;
+ tcflag_t                  c_cflag;
+ int                       opened;
+ int                       socket;
+
+ int                       last_cr;
+ int                       iac_mode;   
+};
+
+#define MAX_PTYS   16
+
+pty_t ptys[MAX_PTYS];
+
+/* This procedure returns the devname for a pty slot free.
+ * If not slot availiable (field socket>=0) 
+ *  then the socket argument is closed
+ */
+
+char *  get_pty(int socket) {
+	int ndx;
+	for (ndx=0;ndx<MAX_PTYS;ndx++) {
+		if (ptys[ndx].socket<0) {
+			ptys[ndx].socket=socket;
+			return ptys[ndx].devname;
+		};
+	};
+	close(socket);
+	return NULL;
+}
+
+
+/*-----------------------------------------------------------*/
+/*
+ * The NVT terminal is negociated in PollRead and PollWrite
+ * with every BYTE sendded or received. 
+ * A litle status machine in the pty_read_byte(int minor) 
+ * 
+ */
+const char IAC_AYT_RSP[]="\r\nAYT? Yes, RTEMS-SHELL is here\r\n";
+const char IAC_BRK_RSP[]="<*Break*>";
+const char IAC_IP_RSP []="<*Interupt*>";
+
+
+static
+int send_iac(int minor,unsigned char mode,unsigned char option) {
+	unsigned char buf[3];
+	buf[0]=IAC_ESC;
+	buf[1]=mode;
+	buf[2]=option;
+	return write(ptys[minor].socket,buf,sizeof(buf));
+}
+
+int read_pty(int minor) { /* Characters writed in the client side*/
+	 unsigned char value;
+	 int count;
+	 int result;
+	 count=read(ptys[minor].socket,&value,sizeof(value));
+	 if (count<1) {
+          fclose(stdin);		 
+          fclose(stdout);		 
+          fclose(stderr);		 
+	  rtems_task_delete(RTEMS_SELF);
+	 };
+	 switch(ptys[minor].iac_mode) {
+          case IAC_ESC:
+	       ptys[minor].iac_mode=0;
+               switch(value) {
+                case IAC_ESC :
+		     return IAC_ESC;
+                case IAC_DONT:
+                case IAC_DO  :
+                case IAC_WONT:
+                case IAC_WILL:
+		     ptys[minor].iac_mode=value;
+		     return -1;
+                case IAC_SB  :
+		     return -100;
+                case IAC_GA  :
+		     return -1;
+                case IAC_EL  :
+		     return 0x03; /* Ctrl-C*/
+                case IAC_EC  :
+		     return '\b';
+		case IAC_AYT :
+	             write(ptys[minor].socket,IAC_AYT_RSP,strlen(IAC_AYT_RSP));
+		     return -1;
+                case IAC_AO  :
+		     return -1;
+                case IAC_IP  :
+	             write(ptys[minor].socket,IAC_IP_RSP,strlen(IAC_IP_RSP));
+		     return -1;
+		case IAC_BRK :
+	             write(ptys[minor].socket,IAC_BRK_RSP,strlen(IAC_BRK_RSP));
+		     return -1;
+                case IAC_DMARK:
+		     return -2;
+                case IAC_NOP :
+		     return -1;
+                case IAC_SE  :
+		     return -101;
+                case IAC_EOR :
+		     return -102;
+		default      :
+		     return -1;
+	       };
+	       break;
+	  case IAC_WILL:
+	       ptys[minor].iac_mode=0;
+	       if (value==34){send_iac(minor,IAC_DONT,   34);       /*LINEMODE*/ 
+	                      send_iac(minor,IAC_DO  ,    1);} else /*ECHO    */
+	                     {send_iac(minor,IAC_DONT,value);};
+	       return -1;
+	  case IAC_DONT:
+	       ptys[minor].iac_mode=0;
+	       return -1;
+	  case IAC_DO  :
+	       ptys[minor].iac_mode=0;
+	       if (value==3) {send_iac(minor,IAC_WILL,    3);} else /* GO AHEAD*/
+	       if (value==1) {                               } else /* ECHO */
+	                     {send_iac(minor,IAC_WONT,value);};
+	       return -1;
+	  case IAC_WONT:
+	       ptys[minor].iac_mode=0;
+	       if (value==1) {send_iac(minor,IAC_WILL,    1);} else /* ECHO */
+	                     {send_iac(minor,IAC_WONT,value);};
+	       return -1;
+	  default:
+	       ptys[minor].iac_mode=0;
+	       if (value==IAC_ESC) {
+                     ptys[minor].iac_mode=value;
+		     return -1;
+	       } else {
+		     result=value;  
+		     if ((value=='\n') && (ptys[minor].last_cr)) result=-1;
+		     ptys[minor].last_cr=(value=='\r');
+		     return result;
+	       };
+	 };
+	
+}
+
+/*-----------------------------------------------------------*/
+static int ptySetAttributes(int minor,const struct termios *t);
+static int ptyPollInitialize(int major,int minor,void * arg) ;
+static int ptyShutdown(int major,int minor,void * arg) ;
+static int ptyPollWrite(int minor, const char * buf,int len) ;
+static int ptyPollRead(int minor) ;
+const rtems_termios_callbacks * pty_get_termios_handlers(int polled) ;
+/*-----------------------------------------------------------*/
+/* Set the 'Hardware'                                        */ 
+/*-----------------------------------------------------------*/
+static int
+ptySetAttributes(int minor,const struct termios *t) {
+	if (minor<MAX_PTYS) {	
+	 ptys[minor].c_cflag=t->c_cflag;	
+	} else {
+	 return -1;
+	};
+	return 0;
+}
+/*-----------------------------------------------------------*/
+static int 
+ptyPollInitialize(int major,int minor,void * arg) {
+	rtems_libio_open_close_args_t * args = arg;
+	struct termios t;
+        if (minor<MAX_PTYS) {	
+         if (ptys[minor].socket<0) return -1;		
+	 ptys[minor].opened=TRUE;
+	 ptys[minor].ttyp=args->iop->data1;
+	 t.c_cflag=B9600|CS8;/* termios default */
+	 return ptySetAttributes(minor,&t);
+	} else {
+	 return -1;
+	};
+}
+/*-----------------------------------------------------------*/
+static int 
+ptyShutdown(int major,int minor,void * arg) {
+        if (minor<MAX_PTYS) {	
+	 ptys[minor].opened=FALSE;
+         if (ptys[minor].socket>=0) close(ptys[minor].socket);
+	 ptys[minor].socket=-1;
+	 chown(ptys[minor].devname,2,0);
+	} else {
+	 return -1;
+	};
+	return 0;
+}
+/*-----------------------------------------------------------*/
+/* Write Characters into pty device                          */ 
+/*-----------------------------------------------------------*/
+static int
+ptyPollWrite(int minor, const char * buf,int len) {
+	int count;
+        if (minor<MAX_PTYS) {	
+         if (ptys[minor].socket<0) return -1;		
+	 count=write(ptys[minor].socket,buf,len);
+	} else {
+	 count=-1;
+	};
+	return count;
+}
+/*-----------------------------------------------------------*/
+static void
+ptyStopRemoteTX(int minor) {
+}
+/*-----------------------------------------------------------*/
+static void
+ptyStartRemoteTX(int minor) {
+}
+/*-----------------------------------------------------------*/
+static int
+ptyPollRead(int minor) {
+	int result;
+        if (minor<MAX_PTYS) {	
+         if (ptys[minor].socket<0) return -1;		
+	 result=read_pty(minor);
+	 return result;
+	};
+	return -1;
+}
+/*-----------------------------------------------------------*/
+static const rtems_termios_callbacks pty_poll_callbacks = {
+	ptyPollInitialize,	/* FirstOpen*/
+	ptyShutdown,		/* LastClose*/
+	ptyPollRead,		/* PollRead  */
+	ptyPollWrite,		/* Write */
+	ptySetAttributes,	/* setAttributes */
+	NULL,			/* stopRemoteTX */
+	NULL,			/* StartRemoteTX */
+	0 			/* outputUsesInterrupts */
+};
+/*-----------------------------------------------------------*/
+const rtems_termios_callbacks * pty_get_termios_handlers(int polled) {
+	return &pty_poll_callbacks;
+}
+/*-----------------------------------------------------------*/
+void init_ptys(void) {
+	int ndx;
+	for (ndx=0;ndx<MAX_PTYS;ndx++) {
+		ptys[ndx].devname=malloc(strlen("/dev/ptyXX")+1);
+		sprintf(ptys[ndx].devname,"/dev/pty%X",ndx);
+		ptys[ndx].ttyp=NULL;
+		ptys[ndx].c_cflag=CS8|B9600;
+		ptys[ndx].socket=-1;
+		ptys[ndx].opened=FALSE;
+
+	};
+}
+
+
+/*-----------------------------------------------------------*/
+/*  pty_initialize
+ *
+ *  This routine initializes the pty IO driver.
+ *
+ *  Input parameters: NONE
+ *
+ *  Output parameters:  NONE
+ *
+ *  Return values:
+ */
+/*-----------------------------------------------------------*/
+rtems_device_driver pty_initialize(
+  rtems_device_major_number  major,
+  rtems_device_minor_number  minor,
+  void                      *arg
+)
+{
+  int ndx;	
+  rtems_status_code status ;
+
+  /* 
+   * Set up ptys
+   */
+
+  init_ptys();
+
+  /*
+   * Register the devices
+   */
+  for (ndx=0;ndx<MAX_PTYS;ndx++) {
+   status = rtems_io_register_name(ptys[ndx].devname, major, ndx);
+   if (status != RTEMS_SUCCESSFUL)
+     rtems_fatal_error_occurred(status);
+   chmod(ptys[ndx].devname,0660);
+   chown(ptys[ndx].devname,2,0);
+  };
+  printk("Device: /dev/pty%X../dev/pty%X (%d)pseudo-terminals registered.\n",0,MAX_PTYS-1,MAX_PTYS);
+
+  return RTEMS_SUCCESSFUL;
+}
+
+
+/*
+ *  Open entry point
+ */
+
+rtems_device_driver pty_open(
+  rtems_device_major_number major,
+  rtems_device_minor_number minor,
+  void                    * arg
+)
+{
+  rtems_status_code sc ;
+  sc = rtems_termios_open(major,minor,arg,pty_get_termios_handlers(FALSE));
+  return sc;
+}
+ 
+/*
+ *  Close entry point
+ */
+
+rtems_device_driver pty_close(
+  rtems_device_major_number major,
+  rtems_device_minor_number minor,
+  void                    * arg
+)
+{
+  return rtems_termios_close(arg);
+}
+
+/*
+ * read bytes from the pty
+ */
+
+rtems_device_driver pty_read(
+  rtems_device_major_number major,
+  rtems_device_minor_number minor,
+  void                    * arg
+)
+{
+  return rtems_termios_read(arg);
+}
+
+/*
+ * write bytes to the pty
+ */
+
+rtems_device_driver pty_write(
+  rtems_device_major_number major,
+  rtems_device_minor_number minor,
+  void                    * arg
+)
+{
+  return rtems_termios_write(arg);
+}
+
+/*
+ *  IO Control entry point
+ */
+
+rtems_device_driver pty_control(
+  rtems_device_major_number major,
+  rtems_device_minor_number minor,
+  void                    * arg
+)
+{
+  return rtems_termios_ioctl(arg);
+}
Index: c/src/libmisc/shell/shell.c
===================================================================
--- c/src/libmisc/shell/shell.c	(revision e565720aadd79ad42f8bac7a5d9aab1a7ad2e5a7)
+++ c/src/libmisc/shell/shell.c	(revision b2712e35b948d7ab37cf6ef46bcdfea678506444)
@@ -13,4 +13,7 @@
  *  $Id$
  */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
 
 #include <stdio.h>
@@ -20,4 +23,6 @@
 #include <rtems/libio.h>
 #include <rtems/libio_.h> 
+#include <rtems/system.h> 
+#include <rtems/shell.h>
 
 #include <termios.h>
@@ -27,6 +32,6 @@
 #include <unistd.h>
 #include <errno.h>
-
-#include <rtems/shell.h>
+#include <pwd.h>
+
 /* ----------------------------------------------- *
  * This is a stupidity but is cute.
@@ -276,11 +281,19 @@
   int c,col;
   col=0;
+  tcdrain(fileno(out));
   for (;;) {
    line[col]=0;	  
    c=fgetc(in);
    switch (c) {
+    case 0x04:/*Control-d*/
+	      if (col) break;
     case EOF :return 0;
+    case '\n':break;
+    case '\f':if (out) fputc('\f',out);
+    case 0x03:/*Control-C*/
+	      line[0]=0; 
     case '\r':if (out) fputc('\n',out);
 	      return 1;
+    case  127:
     case '\b':if (col) {
 	       if (out) {
@@ -302,5 +315,6 @@
 		};
 	      } else {
-	        if (out) fputc('\a',out);
+	        if (out) 
+		 if (c=='\a') fputc('\a',out);
 	      };
 	      break;
@@ -318,4 +332,99 @@
 extern char **environ;	  
 
+void cat_file(FILE * out,char * name) {
+	FILE * fd;
+	int c;
+	if (out) {
+	  fd=fopen(name,"r");
+	  if (fd) {
+  	   while ((c=fgetc(fd))!=EOF) fputc(c,out);
+	   fclose(fd);
+	  };
+	};  
+}
+
+int shell_login(FILE * in,FILE * out) {
+	FILE * fd;
+	int c;
+	time_t t;
+	int times;
+	char name[128];
+	char pass[128];
+	struct passwd * passwd;
+        setuid(0);
+        setgid(0);
+        rtems_current_user_env->euid=
+        rtems_current_user_env->egid=0;
+	if (out) {
+         if((current_shell_env->devname[5]!='p')||
+            (current_shell_env->devname[6]!='t')||
+            (current_shell_env->devname[7]!='y')) {
+	   cat_file(out,"/etc/issue"); 
+	 } else {  
+	  fd=fopen("/etc/issue.net","r");
+	  if (fd) {
+  	   while ((c=fgetc(fd))!=EOF) {
+ 	    if (c=='%')  {
+             switch(c=fgetc(fd)) {
+	      case 't':fprintf(out,"%s",current_shell_env->devname);
+	 	      break;
+	      case 'h':fprintf(out,"0");
+		      break;
+              case 'D':fprintf(out," ");
+		      break;
+              case 'd':time(&t);
+		      fprintf(out,"%s",ctime(&t));
+		      break;
+              case 's':fprintf(out,"RTEMS");
+		      break;
+              case 'm':fprintf(out,"(" CPU_NAME "/" CPU_MODEL_NAME ")");
+		      break;
+              case 'r':fprintf(out,_RTEMS_version);
+		      break;
+              case 'v':fprintf(out,"%s\n%s",_RTEMS_version,_Copyright_Notice);
+		      break;
+              case '%':fprintf(out,"%%");
+		      break;
+	      default :fprintf(out,"%%%c",c);
+		      break;
+	     };
+ 	    } else {
+             fputc(c,out);				
+	    }; 
+	   };
+	   fclose(fd);
+	  } 
+	 };
+ 	};
+	times=0;
+	for (;;) {
+		times++;
+		if (times>3) break;
+		if (out) fprintf(out,"\nlogin: ");
+                if (!shell_scanline(name,sizeof(name),in,out )) break;
+		if (out) fprintf(out,"Password: ");
+                if (!shell_scanline(pass,sizeof(pass),in,NULL)) break;
+		if (out) fprintf(out,"\n");
+		if ((passwd=getpwnam(name))) {
+                 setuid(passwd->pw_uid);			
+                 setgid(passwd->pw_gid);			
+		 rtems_current_user_env->euid=
+		 rtems_current_user_env->egid=0;
+		 chown(current_shell_env->devname,passwd->pw_uid,0);
+		 rtems_current_user_env->euid=passwd->pw_uid;			
+		 rtems_current_user_env->egid=passwd->pw_gid;			
+		 if (!strcmp(passwd->pw_passwd,"*")) {
+		 /* /etc/shadow */
+		  return 0;
+		 } else {
+		  /* crypt() */
+		  return 0;
+		 };
+		};
+		if (out) fprintf(out,"Login incorrect\n");
+	};
+	return -1;
+}
+
 rtems_task shell_shell(rtems_task_argument task_argument) {
 
@@ -327,6 +436,6 @@
   struct termios term;	
   char * devname;
-  char * curdir;
-
+
+  char curdir[256];
   char cmd[256];
   char last_cmd[256]; /* to repeat 'r' */
@@ -334,21 +443,24 @@
   char * argv[128];
 
+  sc=rtems_task_variable_add(RTEMS_SELF,(void*)&current_shell_env,free);
+  if (sc!=RTEMS_SUCCESSFUL) {
+   rtems_error(sc,"rtems_task_variable_add(current_shell_env):");	 
+   rtems_task_delete(RTEMS_SELF);
+  }; 
+
+  current_shell_env=shell_env;  
+  
   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;
+  setuid(0);
+  setgid(0);
+  rtems_current_user_env->euid=
+  rtems_current_user_env->egid=0;
 
   stdin =fopen(devname,"r+");
@@ -356,5 +468,4 @@
   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);
   };
@@ -364,5 +475,5 @@
    term.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
    term.c_oflag &= ~OPOST;
-   term.c_oflag |= (OPOST|ONLCR);
+   term.c_oflag |= (OPOST|ONLCR); /* But with cr+nl on output */
    term.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
    term.c_cflag  = CLOCAL | CREAD |(shell_env->tcflag);
@@ -386,44 +497,51 @@
   };
   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;
+  do {
+  if (!shell_login(stdin,stdout))  {
+   cat_file(stdout,"/etc/motd");
+   strcpy(last_cmd,"");
+   strcpy(cmd,"");
+   printf("\n"
+          "RTEMS SHELL (Version 1.0-FRC):%s. "__DATE__". 'help' to list commands.\n",devname);
+   chdir("/");
+   shell_env->exit_shell=FALSE;
+   for (;;) {
+    /* Prompt section */	  
+    /* XXX: show_prompt user adjustable */
+    getcwd(curdir,sizeof(curdir));
+    printf("%s [%s] %c ",shell_env->taskname,curdir,geteuid()?'$':'#');
+    /* getcmd section */	  
+    if (!shell_scanline(cmd,sizeof(cmd),stdin,stdout)) break; /*EOF*/
+    /* 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) {
+      shell_env->errorlevel=shell_cmd->command(argc,argv);
+     } else {
+      printf("shell:%s command not found\n",argv[0]);
+      shell_env->errorlevel=-1;
+     };
     };
-   };
-   /* end exec cmd section */	  
-  };
-  free(curdir);
+    /* end exec cmd section */	  
+    if (shell_env->exit_shell)  break;
+   };
+   printf("\nGoodbye from RTEMS SHELL :-(\n");
+  };
+  } while (shell_env->forever);
+  fclose(stdin );
+  fclose(stdout); 
+  fclose(stderr);
   rtems_task_delete(RTEMS_SELF);
 }
@@ -433,5 +551,6 @@
 				rtems_task_priority task_priority,
 				char * devname,
-				tcflag_t tcflag) {
+				tcflag_t tcflag,
+				int forever) {
  rtems_id task_id;
  rtems_status_code sc;
@@ -440,5 +559,5 @@
  		     task_priority,
 		     task_stacksize?task_stacksize:RTEMS_MINIMUM_STACK_SIZE,
-		     (RTEMS_DEFAULT_MODES&~RTEMS_ASR_MASK)|RTEMS_ASR,
+		     RTEMS_DEFAULT_MODES,
 		     RTEMS_DEFAULT_ATTRIBUTES,
 		     &task_id);
@@ -455,15 +574,18 @@
  };
  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;
+  global_shell_env.magic     =new_rtems_name("SENV");
+  global_shell_env.devname   ="/dev/console";
+  global_shell_env.taskname  ="GLOBAL";
+  global_shell_env.tcflag    =0;
+  global_shell_env.exit_shell=0;
+  global_shell_env.forever   =TRUE;
  }; 
- shell_env->magic   =global_shell_env.magic; 
- shell_env->devname =devname;
- shell_env->taskname=task_name;
- shell_env->tcflag  =tcflag;
+ shell_env->magic     =global_shell_env.magic; 
+ shell_env->devname   =devname;
+ shell_env->taskname  =task_name;
+ shell_env->tcflag    =tcflag;
+ shell_env->exit_shell=FALSE;
+ shell_env->forever   =forever;
  return rtems_task_start(task_id,shell_shell,(rtems_task_argument) shell_env);
 }
 /* ----------------------------------------------- */
-
Index: c/src/libmisc/shell/shell.h
===================================================================
--- c/src/libmisc/shell/shell.h	(revision e565720aadd79ad42f8bac7a5d9aab1a7ad2e5a7)
+++ c/src/libmisc/shell/shell.h	(revision b2712e35b948d7ab37cf6ef46bcdfea678506444)
@@ -46,4 +46,6 @@
   tcflag_t tcflag;
   /* user extensions */
+  int  exit_shell; /* logout */
+  int  forever   ; /* repeat login */
   int  errorlevel;
   int  mdump_adr;
@@ -51,4 +53,5 @@
 
 int shell_scanline(char * line,int size,FILE * in,FILE * out) ;
+void cat_file(FILE * out,char *name);
 	
 rtems_status_code shell_init(char * task_name      ,
@@ -56,8 +59,45 @@
 		              rtems_task_priority task_priority ,
                               char * devname      ,
-			      tcflag_t tcflag     );
+			      tcflag_t tcflag     ,
+			      int forever         );	
 
 extern shell_env_t global_shell_env,
                 *  current_shell_env;
+/*--------*/
+/* pty.c */ 
+/*--------*/
+
+char * get_pty(int socket);
+
+
+rtems_device_driver pty_initialize(
+  rtems_device_major_number  major,
+  rtems_device_minor_number  minor,
+  void                      *arg);
+rtems_device_driver pty_open(
+  rtems_device_major_number major,
+  rtems_device_minor_number minor,
+  void                    * arg);
+rtems_device_driver pty_close(
+  rtems_device_major_number major,
+  rtems_device_minor_number minor,
+  void                    * arg);
+rtems_device_driver pty_read(
+  rtems_device_major_number major,
+  rtems_device_minor_number minor,
+  void                    * arg);
+rtems_device_driver pty_write(
+  rtems_device_major_number major,
+  rtems_device_minor_number minor,
+  void                    * arg);
+rtems_device_driver pty_control(
+  rtems_device_major_number major,
+  rtems_device_minor_number minor,
+  void                    * arg);
+
+
+#define PTY_DRIVER_TABLE_ENTRY \
+       { pty_initialize , pty_open , pty_close , \
+	 pty_read , pty_write , pty_control }
 /*--------*/
 /* cmds.c */ 
Index: c/src/libmisc/shell/telnetd.c
===================================================================
--- c/src/libmisc/shell/telnetd.c	(revision b2712e35b948d7ab37cf6ef46bcdfea678506444)
+++ c/src/libmisc/shell/telnetd.c	(revision b2712e35b948d7ab37cf6ef46bcdfea678506444)
@@ -0,0 +1,107 @@
+/*
+ *  $Id$
+ */
+
+#include <rtems.h>
+#include <rtems/error.h>
+#include <rtems/shell.h>
+#include <rtems/telnetd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+/***********************************************************/
+rtems_id            telnetd_task_id      =0;
+rtems_unsigned32    telnetd_stack_size   =16384;
+rtems_task_priority telnetd_task_priority=100;
+/***********************************************************/
+rtems_task rtems_task_telnetd(rtems_task_argument task_argument) {
+	int des_socket,
+	    acp_socket;
+	struct sockaddr_in srv;
+	char * devname;
+	int i=1;
+	int size_adr;
+	if ((des_socket=socket(PF_INET,SOCK_STREAM,0))<0) {
+		perror("socket");
+		rtems_task_delete(RTEMS_SELF);
+	};
+	setsockopt(des_socket,SOL_SOCKET,0,&i,sizeof(i));
+	memset(&srv,0,sizeof(srv));
+	srv.sin_family=AF_INET;
+	srv.sin_port=htons(23);
+	size_adr=sizeof(srv);
+	if ((bind(des_socket,(struct sockaddr *)&srv,size_adr))<0) {
+		perror("bind");
+	        close(des_socket);
+		rtems_task_delete(RTEMS_SELF);
+	};
+	if ((listen(des_socket,5))<0) {
+		perror("listen");
+	        close(des_socket);
+		rtems_task_delete(RTEMS_SELF);
+	};
+	do {
+	  acp_socket=accept(des_socket,(struct sockaddr*)&srv,&size_adr);
+	  if (acp_socket<0) {
+		perror("accept");
+		break;
+	  };
+	  if (devname = get_pty(acp_socket) ) {
+	   shell_init(&devname[5],
+		      telnetd_stack_size,
+		      telnetd_task_priority,
+		      devname,B9600|CS8,FALSE);
+	  } else {
+           close(acp_socket);
+	  };
+	} while(1);
+	close(des_socket);
+	rtems_task_delete(RTEMS_SELF);
+}
+/***********************************************************/
+int rtems_initialize_telnetd(void) {
+	rtems_status_code sc;
+	if (telnetd_task_id         ) return RTEMS_RESOURCE_IN_USE;
+	if (telnetd_stack_size<=0   ) telnetd_stack_size   =16384;
+	if (telnetd_task_priority<=2) telnetd_task_priority=100;
+	sc=rtems_task_create(new_rtems_name("TLND"),
+			     100,RTEMS_MINIMUM_STACK_SIZE,	
+			     RTEMS_DEFAULT_MODES,
+			     RTEMS_DEFAULT_ATTRIBUTES,
+			     &telnetd_task_id);
+        if (sc!=RTEMS_SUCCESSFUL) {
+		rtems_error(sc,"creating task telnetd");
+		return (int)sc;
+	};
+	sc=rtems_task_start(telnetd_task_id,
+			    rtems_task_telnetd,
+			    (rtems_task_argument)NULL);
+        if (sc!=RTEMS_SUCCESSFUL) {
+		rtems_error(sc,"starting task telnetd");
+	};
+	return (int)sc;
+}
+/***********************************************************/
+int main_telnetd(int argc,char * argv[]) {
+	rtems_status_code sc;
+	if (telnetd_task_id) {
+		printf("ERROR:telnetd already started\n");
+		return 1;
+	};
+	if (argc>1) telnetd_stack_size   =str2int(argv[1]);
+	if (argc>2) telnetd_task_priority=str2int(argv[2]);
+	sc=rtems_initialize_telnetd();
+        if (sc!=RTEMS_SUCCESSFUL) return sc;
+	printf("rtems_telnetd() started with stacksize=%u,priority=%d\n",
+                        telnetd_stack_size,telnetd_task_priority);
+	return 0;
+}
+/***********************************************************/
+int register_telnetd(void) {
+	shell_add_cmd("telnetd","telnet","telnetd [stacksize [tsk_priority]]",main_telnetd);
+	return 0;
+}
+/***********************************************************/
Index: c/src/libmisc/shell/telnetd.h
===================================================================
--- c/src/libmisc/shell/telnetd.h	(revision b2712e35b948d7ab37cf6ef46bcdfea678506444)
+++ c/src/libmisc/shell/telnetd.h	(revision b2712e35b948d7ab37cf6ef46bcdfea678506444)
@@ -0,0 +1,20 @@
+/*
+ *  $Id$
+ */
+
+#ifndef __TELNETD_H
+#define __TELNETD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif	
+
+int rtems_initialize_telnetd(void);
+int main_telnetd(int argc,char * argv[]);
+int register_telnetd(void);
+ 
+#ifdef __cplusplus
+}
+#endif	
+
+#endif
Index: c/src/libnetworking/rtems_servers/telnetd.c
===================================================================
--- c/src/libnetworking/rtems_servers/telnetd.c	(revision b2712e35b948d7ab37cf6ef46bcdfea678506444)
+++ c/src/libnetworking/rtems_servers/telnetd.c	(revision b2712e35b948d7ab37cf6ef46bcdfea678506444)
@@ -0,0 +1,107 @@
+/*
+ *  $Id$
+ */
+
+#include <rtems.h>
+#include <rtems/error.h>
+#include <rtems/shell.h>
+#include <rtems/telnetd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+/***********************************************************/
+rtems_id            telnetd_task_id      =0;
+rtems_unsigned32    telnetd_stack_size   =16384;
+rtems_task_priority telnetd_task_priority=100;
+/***********************************************************/
+rtems_task rtems_task_telnetd(rtems_task_argument task_argument) {
+	int des_socket,
+	    acp_socket;
+	struct sockaddr_in srv;
+	char * devname;
+	int i=1;
+	int size_adr;
+	if ((des_socket=socket(PF_INET,SOCK_STREAM,0))<0) {
+		perror("socket");
+		rtems_task_delete(RTEMS_SELF);
+	};
+	setsockopt(des_socket,SOL_SOCKET,0,&i,sizeof(i));
+	memset(&srv,0,sizeof(srv));
+	srv.sin_family=AF_INET;
+	srv.sin_port=htons(23);
+	size_adr=sizeof(srv);
+	if ((bind(des_socket,(struct sockaddr *)&srv,size_adr))<0) {
+		perror("bind");
+	        close(des_socket);
+		rtems_task_delete(RTEMS_SELF);
+	};
+	if ((listen(des_socket,5))<0) {
+		perror("listen");
+	        close(des_socket);
+		rtems_task_delete(RTEMS_SELF);
+	};
+	do {
+	  acp_socket=accept(des_socket,(struct sockaddr*)&srv,&size_adr);
+	  if (acp_socket<0) {
+		perror("accept");
+		break;
+	  };
+	  if (devname = get_pty(acp_socket) ) {
+	   shell_init(&devname[5],
+		      telnetd_stack_size,
+		      telnetd_task_priority,
+		      devname,B9600|CS8,FALSE);
+	  } else {
+           close(acp_socket);
+	  };
+	} while(1);
+	close(des_socket);
+	rtems_task_delete(RTEMS_SELF);
+}
+/***********************************************************/
+int rtems_initialize_telnetd(void) {
+	rtems_status_code sc;
+	if (telnetd_task_id         ) return RTEMS_RESOURCE_IN_USE;
+	if (telnetd_stack_size<=0   ) telnetd_stack_size   =16384;
+	if (telnetd_task_priority<=2) telnetd_task_priority=100;
+	sc=rtems_task_create(new_rtems_name("TLND"),
+			     100,RTEMS_MINIMUM_STACK_SIZE,	
+			     RTEMS_DEFAULT_MODES,
+			     RTEMS_DEFAULT_ATTRIBUTES,
+			     &telnetd_task_id);
+        if (sc!=RTEMS_SUCCESSFUL) {
+		rtems_error(sc,"creating task telnetd");
+		return (int)sc;
+	};
+	sc=rtems_task_start(telnetd_task_id,
+			    rtems_task_telnetd,
+			    (rtems_task_argument)NULL);
+        if (sc!=RTEMS_SUCCESSFUL) {
+		rtems_error(sc,"starting task telnetd");
+	};
+	return (int)sc;
+}
+/***********************************************************/
+int main_telnetd(int argc,char * argv[]) {
+	rtems_status_code sc;
+	if (telnetd_task_id) {
+		printf("ERROR:telnetd already started\n");
+		return 1;
+	};
+	if (argc>1) telnetd_stack_size   =str2int(argv[1]);
+	if (argc>2) telnetd_task_priority=str2int(argv[2]);
+	sc=rtems_initialize_telnetd();
+        if (sc!=RTEMS_SUCCESSFUL) return sc;
+	printf("rtems_telnetd() started with stacksize=%u,priority=%d\n",
+                        telnetd_stack_size,telnetd_task_priority);
+	return 0;
+}
+/***********************************************************/
+int register_telnetd(void) {
+	shell_add_cmd("telnetd","telnet","telnetd [stacksize [tsk_priority]]",main_telnetd);
+	return 0;
+}
+/***********************************************************/
Index: c/src/libnetworking/rtems_servers/telnetd.h
===================================================================
--- c/src/libnetworking/rtems_servers/telnetd.h	(revision b2712e35b948d7ab37cf6ef46bcdfea678506444)
+++ c/src/libnetworking/rtems_servers/telnetd.h	(revision b2712e35b948d7ab37cf6ef46bcdfea678506444)
@@ -0,0 +1,20 @@
+/*
+ *  $Id$
+ */
+
+#ifndef __TELNETD_H
+#define __TELNETD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif	
+
+int rtems_initialize_telnetd(void);
+int main_telnetd(int argc,char * argv[]);
+int register_telnetd(void);
+ 
+#ifdef __cplusplus
+}
+#endif	
+
+#endif
Index: cpukit/libmisc/ChangeLog
===================================================================
--- cpukit/libmisc/ChangeLog	(revision e565720aadd79ad42f8bac7a5d9aab1a7ad2e5a7)
+++ cpukit/libmisc/ChangeLog	(revision b2712e35b948d7ab37cf6ef46bcdfea678506444)
@@ -1,2 +1,23 @@
+2000-05-24	Fernando Ruiz Casas <fernando.ruiz@ctv.es>
+
+	* monitor/mon-prmisc.c: Correct print line.
+	* shell/Makefile.am: Added new file telnetd.c.
+	* shell/telnetd.c, shell/telnetd.h, shell/pty.c: New files.
+	* shell/shell.c, shell/cmds.c, shell/shell.h: Numerous improvments:
+	   - The shell_init has a new parameter 'forever' because in
+	     /dev/console you need that this process runs forever but in
+	     tcp/ip not. (respawn?)
+	   - A new task for every session opened trought tcp/ip telnet client.
+	     (the chargen,daytime and more are possible of implementation but
+	     I ask me if they are necesary)
+	   - Exit from the session delete the task and when the client fails too.
+	   - More cmds have been implemented. (very reduced version of these)
+	     umask, chmod, id, whoami, rm, cat, ...
+	   - A reduced line edit has been implemented.
+	       Ctrl-C abort the input,
+	       Ctrl-d in the first position gives EOF (logout).
+	       '\b' and DEL makes the rubout operation.
+	       I think that readline() for every session spents a lot of resources.
+
 2001-04-28	Ralf Corsepius <corsepiu@faw.uni-ulm.de>
 
Index: cpukit/libmisc/monitor/mon-prmisc.c
===================================================================
--- cpukit/libmisc/monitor/mon-prmisc.c	(revision e565720aadd79ad42f8bac7a5d9aab1a7ad2e5a7)
+++ cpukit/libmisc/monitor/mon-prmisc.c	(revision b2712e35b948d7ab37cf6ef46bcdfea678506444)
@@ -109,6 +109,6 @@
         length += rtems_monitor_dump_char(u.c[i]);
 #else
-    for (i=sizeof(u.c)-1; i ; i--)
-        length += rtems_monitor_dump_char(u.c[i]);
+    for (i=0; i<sizeof(u.c); i++)
+        length += rtems_monitor_dump_char(u.c[sizeof(u.c)-1-i]);
 #endif
     return length;
Index: cpukit/libmisc/shell/Makefile.am
===================================================================
--- cpukit/libmisc/shell/Makefile.am	(revision e565720aadd79ad42f8bac7a5d9aab1a7ad2e5a7)
+++ cpukit/libmisc/shell/Makefile.am	(revision b2712e35b948d7ab37cf6ef46bcdfea678506444)
@@ -10,8 +10,8 @@
 LIB = $(ARCH)/$(LIBNAME).a
 
-C_FILES = cmds.c shell.c
+C_FILES = cmds.c shell.c pty.c telnetd.c
 C_O_FILES = $(C_FILES:%.c=$(ARCH)/%.o)
 
-include_rtems_HEADERS = shell.h
+include_rtems_HEADERS = shell.h telnetd.h
 
 OBJS = $(C_O_FILES)
@@ -40,5 +40,5 @@
 .PRECIOUS: $(LIB)
 
-EXTRA_DIST = README shell.c cmds.c shell.h
+EXTRA_DIST = README shell.c cmds.c pty.c telnetd.c shell.h telnetd.h
 
 include $(top_srcdir)/../../../automake/local.am
Index: cpukit/libmisc/shell/README
===================================================================
--- cpukit/libmisc/shell/README	(revision e565720aadd79ad42f8bac7a5d9aab1a7ad2e5a7)
+++ cpukit/libmisc/shell/README	(revision b2712e35b948d7ab37cf6ef46bcdfea678506444)
@@ -20,9 +20,11 @@
     and enjoy it.
 
-
+3.  If you have tcp/ip inited you can start telnetd daemon.
+    You need register pseudo-terminals driver into device drivers table.
+    16 ptyX termios device terminales are created into /dev/.
+    Calling rtems_initialize_telnetd() starts the daemon.
+    Enjoy it.
 
 FUTURE:
 
 1.  Adding new commands in cmds.c to give file manegement to shell.
-
-2.  Create a telnetd daemon. (pseudo-terminal needed)
Index: cpukit/libmisc/shell/cmds.c
===================================================================
--- cpukit/libmisc/shell/cmds.c	(revision e565720aadd79ad42f8bac7a5d9aab1a7ad2e5a7)
+++ cpukit/libmisc/shell/cmds.c	(revision b2712e35b948d7ab37cf6ef46bcdfea678506444)
@@ -14,5 +14,5 @@
  *
  * TODO: A lot of improvements of course. 
- *      cat, cp, rm, mv, ...
+ *      cp, mv, ...
  *      hexdump,
  *      
@@ -35,4 +35,6 @@
 #include <fcntl.h>
 #include <unistd.h>
+#include <pwd.h>
+#include <grp.h>
 #include <errno.h>
 #include <sys/types.h>
@@ -258,4 +260,8 @@
    struct dirent       *dp;
    struct stat         stat_buf;
+   struct passwd     * pwd;
+   struct group      * grp;
+   char * user;
+   char * group;
    char   sbuf[256];
    char   nbuf[1024];
@@ -280,5 +286,9 @@
       { /* 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",
+	 pwd=getpwuid(stat_buf.st_uid);
+	 user=pwd?pwd->pw_name:"nouser";
+	 grp=getgrgid(stat_buf.st_gid);
+	 group=grp?grp->gr_name:"nogrp";
+         printf("%c%c%c%c%c%c%c%c%c%c %3d %6.6s %6.6s %11d %s %s%c\n",
                  (S_ISLNK(stat_buf.st_mode)?('l'):
                     (S_ISDIR(stat_buf.st_mode)?('d'):('-'))),
@@ -293,4 +303,5 @@
                  (stat_buf.st_mode & S_IXOTH)?('x'):('-'),
                  (int)stat_buf.st_nlink,
+	 	 user,group, 
                  (int)stat_buf.st_size,
 		 sbuf,
@@ -351,4 +362,26 @@
  };
  return 0;
+}
+/*-----------------------------------------------------------*/  	
+int main_cat   (int argc, char *argv[])
+{
+   int n;
+   n=1;
+   while (n<argc) cat_file(stdout,argv[n++]);
+   return 0;
+}
+/*-----------------------------------------------------------*/  	
+int main_rm    (int argc, char *argv[])
+{
+   int n;
+   n=1;
+   while (n<argc) {
+    if (unlink(argv[n])) {
+     printf("error %s:rm %s\n",strerror(errno),argv[n]);
+     return -1;
+    };
+    n++;
+   };
+   return 0;
 }
 /*-----------------------------------------------------------*/  	
@@ -425,4 +458,65 @@
   return 0;
 }
+/*-----------------------------------------------------------*/
+int main_logoff(int argc,char *argv[]) 
+{
+  printf("logoff from the system...");	
+  current_shell_env->exit_shell=TRUE;	
+  return 0;
+}
+/*-----------------------------------------------------------*/
+int main_tty   (int argc,char *argv[]) 
+{
+  printf("%s\n",ttyname(fileno(stdin)));
+  return 0;
+}
+/*-----------------------------------------------------------*/
+int main_whoami(int argc,char *argv[]) 
+{
+   struct passwd     * pwd;
+   pwd=getpwuid(getuid());
+   printf("%s\n",pwd?pwd->pw_name:"nobody");
+   return 0;
+}
+/*-----------------------------------------------------------*/
+int main_id    (int argc,char *argv[]) 
+{
+   struct passwd     * pwd;
+   struct group      * grp;
+   pwd=getpwuid(getuid());
+   grp=getgrgid(getgid());
+   printf("uid=%d(%s),gid=%d(%s),",
+		   getuid(),pwd?pwd->pw_name:"",
+		   getgid(),grp?grp->gr_name:"");
+   pwd=getpwuid(geteuid());
+   grp=getgrgid(getegid());
+   printf("euid=%d(%s),egid=%d(%s)\n",
+		   geteuid(),pwd?pwd->pw_name:"",
+		   getegid(),grp?grp->gr_name:"");
+   return 0;
+}
+/*-----------------------------------------------------------*/
+int main_umask(int argc,char *argv[]) 
+{
+   mode_t msk=umask(0);
+   if (argc == 2) msk=str2int(argv[1]);
+   umask(msk);
+   msk=umask(0);
+   printf("0%o\n",msk);
+   umask(msk);
+   return 0;
+}
+/*-----------------------------------------------------------*/
+int main_chmod(int argc,char *argv[]) 
+{
+   int n;
+   mode_t mode;
+   if (argc > 2){
+    mode=str2int(argv[1])&0777;
+    n=2;
+    while (n<argc) chmod(argv[n++],mode);
+   };
+   return 0;
+}
 /*-----------------------------------------------------------*  	
  * with this you can call at all the rtems monitor commands.
@@ -443,4 +537,12 @@
   rtems_monitor_command_entry_t *command;
   extern rtems_monitor_command_entry_t rtems_monitor_commands[];
+  /* monitor topic */
+  command=rtems_monitor_commands;
+  while (command) {
+   if (strcmp("exit",command->command)) /*Exclude EXIT (alias quit)*/
+    shell_add_cmd(command->command,"monitor",
+                  command->usage  ,main_monitor);
+   command=command->next;
+  };
   /* dir[ectories] topic */
   shell_add_cmd  ("ls"    ,"dir","ls [dir]     # list files in the directory" ,main_ls   );
@@ -450,4 +552,7 @@
   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_add_cmd  ("cat"   ,"dir","cat n1 [n2 [n3...]]# show the ascii contents",main_cat );
+  shell_add_cmd  ("rm"    ,"dir","rm n1 [n2 [n3...]]# remove files"           ,main_rm   );
+  shell_add_cmd  ("chmod" ,"dir","chmod 0777 n1 n2... #change filemode"       ,main_chmod);
 
   shell_alias_cmd("ls"    ,"dir");
@@ -455,7 +560,14 @@
 
   /* misc. topic */
+  shell_add_cmd  ("logoff","misc","logoff from the system"                    ,main_logoff);
+  shell_alias_cmd("logoff","exit"); 
   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);
+  shell_add_cmd  ("tty"  ,"misc","show ttyname"                               ,main_tty  );
+  shell_add_cmd  ("whoami","misc","show current user"                         ,main_whoami);
+  shell_add_cmd  ("id"    ,"misc","show uid,gid,euid,egid"                    ,main_id    );
+  shell_add_cmd  ("umask" ,"misc","umask [new_umask]"                         ,main_umask );
+
 
   /* memory topic */
@@ -468,11 +580,4 @@
   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;
-  };
-}
-/*-----------------------------------------------------------*/  	
+}
+/*-----------------------------------------------------------*/  	
Index: cpukit/libmisc/shell/shell.c
===================================================================
--- cpukit/libmisc/shell/shell.c	(revision e565720aadd79ad42f8bac7a5d9aab1a7ad2e5a7)
+++ cpukit/libmisc/shell/shell.c	(revision b2712e35b948d7ab37cf6ef46bcdfea678506444)
@@ -13,4 +13,7 @@
  *  $Id$
  */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
 
 #include <stdio.h>
@@ -20,4 +23,6 @@
 #include <rtems/libio.h>
 #include <rtems/libio_.h> 
+#include <rtems/system.h> 
+#include <rtems/shell.h>
 
 #include <termios.h>
@@ -27,6 +32,6 @@
 #include <unistd.h>
 #include <errno.h>
-
-#include <rtems/shell.h>
+#include <pwd.h>
+
 /* ----------------------------------------------- *
  * This is a stupidity but is cute.
@@ -276,11 +281,19 @@
   int c,col;
   col=0;
+  tcdrain(fileno(out));
   for (;;) {
    line[col]=0;	  
    c=fgetc(in);
    switch (c) {
+    case 0x04:/*Control-d*/
+	      if (col) break;
     case EOF :return 0;
+    case '\n':break;
+    case '\f':if (out) fputc('\f',out);
+    case 0x03:/*Control-C*/
+	      line[0]=0; 
     case '\r':if (out) fputc('\n',out);
 	      return 1;
+    case  127:
     case '\b':if (col) {
 	       if (out) {
@@ -302,5 +315,6 @@
 		};
 	      } else {
-	        if (out) fputc('\a',out);
+	        if (out) 
+		 if (c=='\a') fputc('\a',out);
 	      };
 	      break;
@@ -318,4 +332,99 @@
 extern char **environ;	  
 
+void cat_file(FILE * out,char * name) {
+	FILE * fd;
+	int c;
+	if (out) {
+	  fd=fopen(name,"r");
+	  if (fd) {
+  	   while ((c=fgetc(fd))!=EOF) fputc(c,out);
+	   fclose(fd);
+	  };
+	};  
+}
+
+int shell_login(FILE * in,FILE * out) {
+	FILE * fd;
+	int c;
+	time_t t;
+	int times;
+	char name[128];
+	char pass[128];
+	struct passwd * passwd;
+        setuid(0);
+        setgid(0);
+        rtems_current_user_env->euid=
+        rtems_current_user_env->egid=0;
+	if (out) {
+         if((current_shell_env->devname[5]!='p')||
+            (current_shell_env->devname[6]!='t')||
+            (current_shell_env->devname[7]!='y')) {
+	   cat_file(out,"/etc/issue"); 
+	 } else {  
+	  fd=fopen("/etc/issue.net","r");
+	  if (fd) {
+  	   while ((c=fgetc(fd))!=EOF) {
+ 	    if (c=='%')  {
+             switch(c=fgetc(fd)) {
+	      case 't':fprintf(out,"%s",current_shell_env->devname);
+	 	      break;
+	      case 'h':fprintf(out,"0");
+		      break;
+              case 'D':fprintf(out," ");
+		      break;
+              case 'd':time(&t);
+		      fprintf(out,"%s",ctime(&t));
+		      break;
+              case 's':fprintf(out,"RTEMS");
+		      break;
+              case 'm':fprintf(out,"(" CPU_NAME "/" CPU_MODEL_NAME ")");
+		      break;
+              case 'r':fprintf(out,_RTEMS_version);
+		      break;
+              case 'v':fprintf(out,"%s\n%s",_RTEMS_version,_Copyright_Notice);
+		      break;
+              case '%':fprintf(out,"%%");
+		      break;
+	      default :fprintf(out,"%%%c",c);
+		      break;
+	     };
+ 	    } else {
+             fputc(c,out);				
+	    }; 
+	   };
+	   fclose(fd);
+	  } 
+	 };
+ 	};
+	times=0;
+	for (;;) {
+		times++;
+		if (times>3) break;
+		if (out) fprintf(out,"\nlogin: ");
+                if (!shell_scanline(name,sizeof(name),in,out )) break;
+		if (out) fprintf(out,"Password: ");
+                if (!shell_scanline(pass,sizeof(pass),in,NULL)) break;
+		if (out) fprintf(out,"\n");
+		if ((passwd=getpwnam(name))) {
+                 setuid(passwd->pw_uid);			
+                 setgid(passwd->pw_gid);			
+		 rtems_current_user_env->euid=
+		 rtems_current_user_env->egid=0;
+		 chown(current_shell_env->devname,passwd->pw_uid,0);
+		 rtems_current_user_env->euid=passwd->pw_uid;			
+		 rtems_current_user_env->egid=passwd->pw_gid;			
+		 if (!strcmp(passwd->pw_passwd,"*")) {
+		 /* /etc/shadow */
+		  return 0;
+		 } else {
+		  /* crypt() */
+		  return 0;
+		 };
+		};
+		if (out) fprintf(out,"Login incorrect\n");
+	};
+	return -1;
+}
+
 rtems_task shell_shell(rtems_task_argument task_argument) {
 
@@ -327,6 +436,6 @@
   struct termios term;	
   char * devname;
-  char * curdir;
-
+
+  char curdir[256];
   char cmd[256];
   char last_cmd[256]; /* to repeat 'r' */
@@ -334,21 +443,24 @@
   char * argv[128];
 
+  sc=rtems_task_variable_add(RTEMS_SELF,(void*)&current_shell_env,free);
+  if (sc!=RTEMS_SUCCESSFUL) {
+   rtems_error(sc,"rtems_task_variable_add(current_shell_env):");	 
+   rtems_task_delete(RTEMS_SELF);
+  }; 
+
+  current_shell_env=shell_env;  
+  
   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;
+  setuid(0);
+  setgid(0);
+  rtems_current_user_env->euid=
+  rtems_current_user_env->egid=0;
 
   stdin =fopen(devname,"r+");
@@ -356,5 +468,4 @@
   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);
   };
@@ -364,5 +475,5 @@
    term.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
    term.c_oflag &= ~OPOST;
-   term.c_oflag |= (OPOST|ONLCR);
+   term.c_oflag |= (OPOST|ONLCR); /* But with cr+nl on output */
    term.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
    term.c_cflag  = CLOCAL | CREAD |(shell_env->tcflag);
@@ -386,44 +497,51 @@
   };
   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;
+  do {
+  if (!shell_login(stdin,stdout))  {
+   cat_file(stdout,"/etc/motd");
+   strcpy(last_cmd,"");
+   strcpy(cmd,"");
+   printf("\n"
+          "RTEMS SHELL (Version 1.0-FRC):%s. "__DATE__". 'help' to list commands.\n",devname);
+   chdir("/");
+   shell_env->exit_shell=FALSE;
+   for (;;) {
+    /* Prompt section */	  
+    /* XXX: show_prompt user adjustable */
+    getcwd(curdir,sizeof(curdir));
+    printf("%s [%s] %c ",shell_env->taskname,curdir,geteuid()?'$':'#');
+    /* getcmd section */	  
+    if (!shell_scanline(cmd,sizeof(cmd),stdin,stdout)) break; /*EOF*/
+    /* 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) {
+      shell_env->errorlevel=shell_cmd->command(argc,argv);
+     } else {
+      printf("shell:%s command not found\n",argv[0]);
+      shell_env->errorlevel=-1;
+     };
     };
-   };
-   /* end exec cmd section */	  
-  };
-  free(curdir);
+    /* end exec cmd section */	  
+    if (shell_env->exit_shell)  break;
+   };
+   printf("\nGoodbye from RTEMS SHELL :-(\n");
+  };
+  } while (shell_env->forever);
+  fclose(stdin );
+  fclose(stdout); 
+  fclose(stderr);
   rtems_task_delete(RTEMS_SELF);
 }
@@ -433,5 +551,6 @@
 				rtems_task_priority task_priority,
 				char * devname,
-				tcflag_t tcflag) {
+				tcflag_t tcflag,
+				int forever) {
  rtems_id task_id;
  rtems_status_code sc;
@@ -440,5 +559,5 @@
  		     task_priority,
 		     task_stacksize?task_stacksize:RTEMS_MINIMUM_STACK_SIZE,
-		     (RTEMS_DEFAULT_MODES&~RTEMS_ASR_MASK)|RTEMS_ASR,
+		     RTEMS_DEFAULT_MODES,
 		     RTEMS_DEFAULT_ATTRIBUTES,
 		     &task_id);
@@ -455,15 +574,18 @@
  };
  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;
+  global_shell_env.magic     =new_rtems_name("SENV");
+  global_shell_env.devname   ="/dev/console";
+  global_shell_env.taskname  ="GLOBAL";
+  global_shell_env.tcflag    =0;
+  global_shell_env.exit_shell=0;
+  global_shell_env.forever   =TRUE;
  }; 
- shell_env->magic   =global_shell_env.magic; 
- shell_env->devname =devname;
- shell_env->taskname=task_name;
- shell_env->tcflag  =tcflag;
+ shell_env->magic     =global_shell_env.magic; 
+ shell_env->devname   =devname;
+ shell_env->taskname  =task_name;
+ shell_env->tcflag    =tcflag;
+ shell_env->exit_shell=FALSE;
+ shell_env->forever   =forever;
  return rtems_task_start(task_id,shell_shell,(rtems_task_argument) shell_env);
 }
 /* ----------------------------------------------- */
-
Index: cpukit/libmisc/shell/shell.h
===================================================================
--- cpukit/libmisc/shell/shell.h	(revision e565720aadd79ad42f8bac7a5d9aab1a7ad2e5a7)
+++ cpukit/libmisc/shell/shell.h	(revision b2712e35b948d7ab37cf6ef46bcdfea678506444)
@@ -46,4 +46,6 @@
   tcflag_t tcflag;
   /* user extensions */
+  int  exit_shell; /* logout */
+  int  forever   ; /* repeat login */
   int  errorlevel;
   int  mdump_adr;
@@ -51,4 +53,5 @@
 
 int shell_scanline(char * line,int size,FILE * in,FILE * out) ;
+void cat_file(FILE * out,char *name);
 	
 rtems_status_code shell_init(char * task_name      ,
@@ -56,8 +59,45 @@
 		              rtems_task_priority task_priority ,
                               char * devname      ,
-			      tcflag_t tcflag     );
+			      tcflag_t tcflag     ,
+			      int forever         );	
 
 extern shell_env_t global_shell_env,
                 *  current_shell_env;
+/*--------*/
+/* pty.c */ 
+/*--------*/
+
+char * get_pty(int socket);
+
+
+rtems_device_driver pty_initialize(
+  rtems_device_major_number  major,
+  rtems_device_minor_number  minor,
+  void                      *arg);
+rtems_device_driver pty_open(
+  rtems_device_major_number major,
+  rtems_device_minor_number minor,
+  void                    * arg);
+rtems_device_driver pty_close(
+  rtems_device_major_number major,
+  rtems_device_minor_number minor,
+  void                    * arg);
+rtems_device_driver pty_read(
+  rtems_device_major_number major,
+  rtems_device_minor_number minor,
+  void                    * arg);
+rtems_device_driver pty_write(
+  rtems_device_major_number major,
+  rtems_device_minor_number minor,
+  void                    * arg);
+rtems_device_driver pty_control(
+  rtems_device_major_number major,
+  rtems_device_minor_number minor,
+  void                    * arg);
+
+
+#define PTY_DRIVER_TABLE_ENTRY \
+       { pty_initialize , pty_open , pty_close , \
+	 pty_read , pty_write , pty_control }
 /*--------*/
 /* cmds.c */ 
