summaryrefslogtreecommitdiffstats
path: root/c/src/libmisc/shell/pty.c
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>2001-05-24 21:58:39 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>2001-05-24 21:58:39 +0000
commitb2712e35b948d7ab37cf6ef46bcdfea678506444 (patch)
treee7575dbae5f5861131ac9cf03cdea1bfc7447269 /c/src/libmisc/shell/pty.c
parent2000-05-24 Fernando Ruiz Casas <fernando.ruiz@ctv.es> (diff)
downloadrtems-b2712e35b948d7ab37cf6ef46bcdfea678506444.tar.bz2
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.
Diffstat (limited to '')
-rw-r--r--c/src/libmisc/shell/pty.c406
1 files changed, 406 insertions, 0 deletions
diff --git a/c/src/libmisc/shell/pty.c b/c/src/libmisc/shell/pty.c
new file mode 100644
index 0000000000..d6077a566a
--- /dev/null
+++ b/c/src/libmisc/shell/pty.c
@@ -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);
+}