diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-04-30 11:07:05 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2018-04-30 13:42:18 +0200 |
commit | 443a058db4ee8032221da84823f39f411796ff63 (patch) | |
tree | db5850817d66462ff2f869dfb19c0f0840282cc8 /rtemsbsd/telnetd/pty.c | |
parent | b1404f23928a7be109ba48db972031719ed4a535 (diff) |
Use network services from RTEMS
Close #3419.
Diffstat (limited to 'rtemsbsd/telnetd/pty.c')
-rw-r--r-- | rtemsbsd/telnetd/pty.c | 660 |
1 files changed, 0 insertions, 660 deletions
diff --git a/rtemsbsd/telnetd/pty.c b/rtemsbsd/telnetd/pty.c deleted file mode 100644 index 727e5ebf..00000000 --- a/rtemsbsd/telnetd/pty.c +++ /dev/null @@ -1,660 +0,0 @@ -/* - * /dev/ptyXX (Support for pseudo-terminals) - * - * Original 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. - * - * Till Straumann <strauman@slac.stanford.edu> - * - * - converted into a loadable module - * - NAWS support / ioctls for querying/setting the window - * size added. - * - don't delete the running task when the connection - * is closed. Rather let 'read()' return a 0 count so - * they may cleanup. Some magic hack works around termios - * limitation. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#define DEBUG_WH (1<<0) -#define DEBUG_DETAIL (1<<1) - -/* #define DEBUG DEBUG_WH */ - -/*-----------------------------------------*/ -#include <termios.h> -#include <rtems/termiostypes.h> -#include <sys/ttycom.h> -#include <rtems.h> -#include <rtems/libio.h> -#include <rtems/bspIo.h> -#include <errno.h> -#include <sys/socket.h> -/*-----------------------------------------*/ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <syslog.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 - -#define SB_MAX 16 - -extern int rtems_telnetd_maximum_ptys; - -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; - unsigned iac_mode; - unsigned char sb_buf[SB_MAX]; - int sb_ind; - int width; - int height; -}; - - -static int telnet_pty_inited=FALSE; -static pty_t *telnet_ptys; - -static rtems_device_major_number pty_major; - -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(telnet_ptys[minor].socket,buf,sizeof(buf)); -} - -/* This procedure returns the devname for a pty slot free. - * If not slot availiable (field socket>=0) - * then the socket argument is closed - */ - -char * telnet_get_pty(int socket) -{ - int ndx; - - if (telnet_pty_inited) { -#if 0 - if ( rtems_telnetd_maximum_ptys < 5 ) - rtems_telnetd_maximum_ptys = 5; - - telnet_ptys = malloc( rtems_telnetd_maximum_ptys * sizeof (pty_t) ); -#endif - if ( !telnet_ptys ) { - return NULL; - } - - for (ndx=0;ndx<rtems_telnetd_maximum_ptys;ndx++) { - - if (telnet_ptys[ndx].socket<0) { - struct timeval t; - /* set a long polling interval to save CPU time */ - t.tv_sec=2; - t.tv_usec=00000; - setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(t)); - telnet_ptys[ndx].socket=socket; - - /* inform the client that we will echo */ - send_iac(ndx, IAC_WILL, 1); - - return telnet_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) - * - */ -static const char IAC_AYT_RSP[]="\r\nAYT? Yes, RTEMS-SHELL is here\r\n"; -static const char IAC_BRK_RSP[]="<*Break*>"; -static const char IAC_IP_RSP []="<*Interrupt*>"; - -static int -handleSB(pty_t *pty) -{ - switch (pty->sb_buf[0]) { - case 31: /* NAWS */ - pty->width = (pty->sb_buf[1]<<8) + pty->sb_buf[2]; - pty->height = (pty->sb_buf[3]<<8) + pty->sb_buf[4]; -#if DEBUG & DEBUG_WH - fprintf(stderr, - "Setting width/height to %ix%i\n", - pty->width, - pty->height); -#endif - break; - default: - break; - } - return 0; -} - -static int read_pty(int minor) -{ /* Characters written to the client side*/ - unsigned char value; - unsigned int omod; - int count; - int result; - pty_t *pty=telnet_ptys+minor; - - count=read(pty->socket,&value,sizeof(value)); - if (count<0) - return -1; - - if (count<1) { - /* Unfortunately, there is no way of passing an EOF - * condition through the termios driver. Hence, we - * resort to an ugly hack. Setting cindex>ccount - * causes the termios driver to return a read count - * of '0' which is what we want here. We leave - * 'errno' untouched. - */ - pty->ttyp->cindex=pty->ttyp->ccount+1; - return pty->ttyp->termios.c_cc[VEOF]; - }; - - omod=pty->iac_mode; - pty->iac_mode=0; - switch(omod & 0xff) { - case IAC_ESC: - switch(value) { - case IAC_ESC : - /* in case this is an ESC ESC sequence in SB mode */ - pty->iac_mode = omod>>8; - return IAC_ESC; - case IAC_DONT: - case IAC_DO : - case IAC_WONT: - case IAC_WILL: - pty->iac_mode=value; - return -1; - case IAC_SB : -#if DEBUG & DEBUG_DETAIL - printk("SB\n"); -#endif - pty->iac_mode=value; - pty->sb_ind=0; - return -100; - case IAC_GA : - return -1; - case IAC_EL : - return 0x03; /* Ctrl-C*/ - case IAC_EC : - return '\b'; - case IAC_AYT : - write(pty->socket,IAC_AYT_RSP,strlen(IAC_AYT_RSP)); - return -1; - case IAC_AO : - return -1; - case IAC_IP : - write(pty->socket,IAC_IP_RSP,strlen(IAC_IP_RSP)); - return -1; - case IAC_BRK : - write(pty->socket,IAC_BRK_RSP,strlen(IAC_BRK_RSP)); - return -1; - case IAC_DMARK: - return -2; - case IAC_NOP : - return -1; - case IAC_SE : -#if DEBUG & DEBUG_DETAIL - { - int i; - printk("SE"); - for (i=0; i<pty->sb_ind; i++) - printk(" %02x",pty->sb_buf[i]); - printk("\n"); - } -#endif - handleSB(pty); - return -101; - case IAC_EOR : - return -102; - default : - return -1; - }; - break; - - case IAC_SB: - pty->iac_mode=omod; - if (IAC_ESC==value) { - pty->iac_mode=(omod<<8)|value; - } else { - if (pty->sb_ind < SB_MAX) - pty->sb_buf[pty->sb_ind++]=value; - } - return -1; - - case IAC_WILL: - if (value==34){ - send_iac(minor,IAC_DONT, 34); /*LINEMODE*/ - send_iac(minor,IAC_DO , 1); /*ECHO */ - } else if (value==31) { - send_iac(minor,IAC_DO , 31); /*NAWS */ -#if DEBUG & DEBUG_DETAIL - printk("replied DO NAWS\n"); -#endif - } else { - send_iac(minor,IAC_DONT,value); - } - return -1; - case IAC_DONT: - return -1; - case IAC_DO : - if (value==3) { - send_iac(minor,IAC_WILL, 3); /* GO AHEAD*/ - } else if (value==1) { - send_iac(minor,IAC_WILL, 1); /* ECHO */ - } else { - send_iac(minor,IAC_WONT,value); - }; - return -1; - case IAC_WONT: - if (value==1) { - send_iac(minor,IAC_WILL, 1); - } else { /* ECHO */ - send_iac(minor,IAC_WONT,value); - } - return -1; - default: - if (value==IAC_ESC) { - pty->iac_mode=value; - return -1; - } else { - result=value; - if ( 0 - /* map CRLF to CR for symmetry */ - || ((value=='\n') && pty->last_cr) - /* map telnet CRNUL to CR down here */ - || ((value==0) && pty->last_cr) - ) result=-1; - pty->last_cr=(value=='\r'); - return result; - }; - }; - /* should never get here but keep compiler happy */ - return -1; -} - -/*-----------------------------------------------------------*/ -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 ssize_t ptyPollWrite(int minor, const char * buf, size_t len) ; -static int ptyPollRead(int minor) ; -static const rtems_termios_callbacks * pty_get_termios_handlers(int polled) ; -/*-----------------------------------------------------------*/ -/* Set the 'Hardware' */ -/*-----------------------------------------------------------*/ -static int -ptySetAttributes(int minor,const struct termios *t) { - if (minor<rtems_telnetd_maximum_ptys) { - telnet_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 = (rtems_libio_open_close_args_t*)arg; - struct termios t; - if (minor<rtems_telnetd_maximum_ptys) { - if (telnet_ptys[minor].socket<0) return -1; - telnet_ptys[minor].opened=TRUE; - telnet_ptys[minor].ttyp= (struct rtems_termios_tty *) args->iop->data1; - telnet_ptys[minor].iac_mode=0; - telnet_ptys[minor].sb_ind=0; - telnet_ptys[minor].width=0; - telnet_ptys[minor].height=0; - 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<rtems_telnetd_maximum_ptys) { - telnet_ptys[minor].opened=FALSE; - if (telnet_ptys[minor].socket>=0) close(telnet_ptys[minor].socket); - telnet_ptys[minor].socket=-1; - chown(telnet_ptys[minor].devname,2,0); - } else { - return -1; - } - return 0; -} -/*-----------------------------------------------------------*/ -/* Write Characters into pty device */ -/*-----------------------------------------------------------*/ -static ssize_t -ptyPollWrite(int minor, const char * buf, size_t len) { - size_t count; - if (minor<rtems_telnetd_maximum_ptys) { - if (telnet_ptys[minor].socket<0) - return -1; - count=write(telnet_ptys[minor].socket,buf,len); - } else { - count=-1; - } - return count; -} -/*-----------------------------------------------------------*/ -static int -ptyPollRead(int minor) { - int result; - - if (minor<rtems_telnetd_maximum_ptys) { - if (telnet_ptys[minor].socket<0) - return -1; - result=read_pty(minor); - return result; - } - return -1; -} -/*-----------------------------------------------------------*/ -/* pty_initialize - * - * This routine initializes the pty IO driver. - * - * Input parameters: NONE - * - * Output parameters: NONE - * - * Return values: - */ -/*-----------------------------------------------------------*/ -static -rtems_device_driver my_pty_initialize( - rtems_device_major_number major, - rtems_device_minor_number minor, - void *arg -) -{ - int ndx; - rtems_status_code status; - - if ( rtems_telnetd_maximum_ptys < 5 ) - rtems_telnetd_maximum_ptys = 5; - - telnet_ptys = malloc( rtems_telnetd_maximum_ptys * sizeof (pty_t) ); - - /* - * Set up ptys - */ - - for (ndx=0;ndx<rtems_telnetd_maximum_ptys;ndx++) { - telnet_ptys[ndx].devname = (char*)malloc(strlen("/dev/ptyXX")+1); - sprintf(telnet_ptys[ndx].devname,"/dev/pty%X",ndx); - telnet_ptys[ndx].ttyp = NULL; - telnet_ptys[ndx].c_cflag = CS8|B9600; - telnet_ptys[ndx].socket = -1; - telnet_ptys[ndx].opened = FALSE; - telnet_ptys[ndx].sb_ind = 0; - telnet_ptys[ndx].width = 0; - telnet_ptys[ndx].height = 0; - - } - - /* - * Register the devices - */ - for (ndx=0;ndx<rtems_telnetd_maximum_ptys;ndx++) { - status = rtems_io_register_name(telnet_ptys[ndx].devname, major, ndx); - if (status != RTEMS_SUCCESSFUL) - rtems_fatal_error_occurred(status); - chmod(telnet_ptys[ndx].devname,0660); - chown(telnet_ptys[ndx].devname,2,0); /* tty,root*/ - }; - syslog( - LOG_KERN | LOG_INFO, - "/dev/pty%X../dev/pty%X (%d) pseudo-terminals registered.\n", - 0, - rtems_telnetd_maximum_ptys - 1, - rtems_telnetd_maximum_ptys - ); - - return RTEMS_SUCCESSFUL; -} - -static int pty_do_finalize(void) -{ - int ndx; - rtems_status_code status; - - if ( !telnet_pty_inited ) - return 0; - - for (ndx=0;ndx<rtems_telnetd_maximum_ptys;ndx++) { - if (telnet_ptys[ndx].opened) { - fprintf(stderr, - "There are still opened PTY devices, unable to proceed\n"); - return -1; - } - } - if (RTEMS_SUCCESSFUL != rtems_io_unregister_driver(pty_major)) { - fprintf(stderr,"Unable to remove this driver\n"); - return -1; - } - for (ndx=0;ndx<rtems_telnetd_maximum_ptys;ndx++) { - /* rtems_io_register_name() actually creates a node in the filesystem - * (mknod()) - */ - status = (rtems_status_code)unlink(telnet_ptys[ndx].devname); - if (status != RTEMS_SUCCESSFUL) - perror("removing pty device node from file system"); - else - free(telnet_ptys[ndx].devname); - }; - - free ( telnet_ptys ); - - fprintf(stderr,"PTY driver unloaded successfully\n"); - telnet_pty_inited=FALSE; - return 0; -} - -/* - * Open entry point - */ - -static -rtems_device_driver my_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 - */ - -static -rtems_device_driver my_pty_close( - rtems_device_major_number major, - rtems_device_minor_number minor, - void * arg -) -{ - return rtems_termios_close(arg); -} - -/* - * read bytes from the pty - */ - -static -rtems_device_driver my_pty_read( - rtems_device_major_number major, - rtems_device_minor_number minor, - void * arg -) -{ - return rtems_termios_read(arg); -} - -/* - * write bytes to the pty - */ - -static -rtems_device_driver my_pty_write( - rtems_device_major_number major, - rtems_device_minor_number minor, - void * arg -) -{ - return rtems_termios_write(arg); -} - -/* - * IO Control entry point - */ - -static -rtems_device_driver my_pty_control( - rtems_device_major_number major, - rtems_device_minor_number minor, - void * arg -) -{ - rtems_libio_ioctl_args_t *args = (rtems_libio_ioctl_args_t*)arg; - struct winsize *wp = (struct winsize*)args->buffer; - pty_t *p = &telnet_ptys[minor]; - - switch (args->command) { - - case TIOCGWINSZ: - - wp->ws_row = p->height; - wp->ws_col = p->width; - args->ioctl_return=0; -#if DEBUG & DEBUG_WH - fprintf(stderr, - "ioctl(TIOCGWINSZ), returning %ix%i\n", - wp->ws_col, - wp->ws_row); -#endif - - return RTEMS_SUCCESSFUL; - - case TIOCSWINSZ: -#if DEBUG & DEBUG_WH - fprintf(stderr, - "ioctl(TIOCGWINSZ), setting %ix%i\n", - wp->ws_col, - wp->ws_row); -#endif - - p->height = wp->ws_row; - p->width = wp->ws_col; - args->ioctl_return=0; - - return RTEMS_SUCCESSFUL; - - default: - - break; - } - - return rtems_termios_ioctl(arg); -} - -static rtems_driver_address_table drvPty = { - my_pty_initialize, - my_pty_open, - my_pty_close, - my_pty_read, - my_pty_write, - my_pty_control -}; - -/*-----------------------------------------------------------*/ -static const rtems_termios_callbacks pty_poll_callbacks = { - ptyPollInitialize, /* FirstOpen */ - ptyShutdown, /* LastClose */ - ptyPollRead, /* PollRead */ - ptyPollWrite, /* Write */ - ptySetAttributes, /* setAttributes */ - NULL, /* stopRemoteTX */ - NULL, /* StartRemoteTX */ - 0 /* outputUsesInterrupts */ -}; -/*-----------------------------------------------------------*/ -static const rtems_termios_callbacks * pty_get_termios_handlers(int polled) { - return &pty_poll_callbacks; -} -/*-----------------------------------------------------------*/ - -static int pty_do_initialize(void) -{ - if ( !telnet_pty_inited ) { - if (RTEMS_SUCCESSFUL==rtems_io_register_driver(0, &drvPty, &pty_major)) - telnet_pty_inited=TRUE; - else - fprintf(stderr,"WARNING: registering the PTY driver FAILED\n"); - } - return telnet_pty_inited; -} - -int telnet_pty_initialize(void) -{ - return pty_do_initialize(); -} - -int telnet_pty_finalize(void) -{ - return pty_do_finalize(); -} |