From b980f363069cd7d44598188ce0de732fdd7e19f3 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Tue, 25 Sep 2018 15:07:35 +0200 Subject: telnetd: Convert pty driver to new Termios API Update #3526. --- cpukit/telnetd/pty.c | 474 ++++++++++------------------------------------- cpukit/telnetd/telnetd.c | 58 +++--- 2 files changed, 127 insertions(+), 405 deletions(-) (limited to 'cpukit/telnetd') diff --git a/cpukit/telnetd/pty.c b/cpukit/telnetd/pty.c index 3c511f9e98..e32d2eacb9 100644 --- a/cpukit/telnetd/pty.c +++ b/cpukit/telnetd/pty.c @@ -29,16 +29,13 @@ /* #define DEBUG DEBUG_WH */ /*-----------------------------------------*/ -#include -#include #include -#include -#include -#include #include +#include #include #include /*-----------------------------------------*/ +#include #include #include #include @@ -63,42 +60,38 @@ #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[17]; - 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; +#define SB_MAX RTEMS_PTY_SB_MAX + +static bool ptyPollInitialize(rtems_termios_tty *, + rtems_termios_device_context *, struct termios *, + rtems_libio_open_close_args_t *); +static void ptyShutdown(rtems_termios_tty *, + rtems_termios_device_context *, rtems_libio_open_close_args_t *); +static void ptyPollWrite(rtems_termios_device_context *, const char *, size_t); +static int ptyPollRead(rtems_termios_device_context *); +static bool ptySetAttributes(rtems_termios_device_context *, + const struct termios *); +static int my_pty_control(rtems_termios_device_context *, + ioctl_command_t, void *); + +static const rtems_termios_device_handler pty_handler = { + .first_open = ptyPollInitialize, + .last_close = ptyShutdown, + .poll_read = ptyPollRead, + .write = ptyPollWrite, + .set_attributes = ptySetAttributes, + .ioctl = my_pty_control }; - -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) +int send_iac(rtems_pty_context *pty, 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)); + return write(pty->socket, buf, sizeof(buf)); } /* This procedure returns the devname for a pty slot free. @@ -106,43 +99,32 @@ int send_iac(int minor,unsigned char mode,unsigned char option) * then the socket argument is closed */ -char * telnet_get_pty(int socket) +char *telnet_get_pty(rtems_pty_context *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;ndxname, sizeof(pty->name), "/dev/pty%" PRIuPTR, (uintptr_t)pty); + rtems_termios_device_context_initialize(&pty->base, "pty"); + pty->socket = socket; + sc = rtems_termios_device_install(pty->name, &pty_handler, NULL, &pty->base); + if (sc != RTEMS_SUCCESSFUL) { + close(socket); + return NULL; + } - 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; + /* 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)); - /* inform the client that we will echo */ - send_iac(ndx, IAC_WILL, 1); + /* inform the client that we will echo */ + send_iac(pty, IAC_WILL, 1); - return telnet_ptys[ndx].devname; - }; - }; - } - close(socket); - return NULL; + return pty->name; } - /*-----------------------------------------------------------*/ /* * The NVT terminal is negociated in PollRead and PollWrite @@ -155,7 +137,7 @@ static const char IAC_BRK_RSP[]="<*Break*>"; static const char IAC_IP_RSP []="<*Interrupt*>"; static int -handleSB(pty_t *pty) +handleSB(rtems_pty_context *pty) { switch (pty->sb_buf[0]) { case 31: /* NAWS */ @@ -174,13 +156,13 @@ handleSB(pty_t *pty) return 0; } -static int read_pty(int minor) +static int ptyPollRead(rtems_termios_device_context *base) { /* Characters written to the client side*/ + rtems_pty_context *pty = (rtems_pty_context *)base; 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) @@ -272,33 +254,33 @@ static int read_pty(int minor) case IAC_WILL: if (value==34){ - send_iac(minor,IAC_DONT, 34); /*LINEMODE*/ - send_iac(minor,IAC_DO , 1); /*ECHO */ + send_iac(pty,IAC_DONT, 34); /*LINEMODE*/ + send_iac(pty,IAC_DO , 1); /*ECHO */ } else if (value==31) { - send_iac(minor,IAC_DO , 31); /*NAWS */ + send_iac(pty,IAC_DO , 31); /*NAWS */ #if DEBUG & DEBUG_DETAIL printk("replied DO NAWS\n"); #endif } else { - send_iac(minor,IAC_DONT,value); + send_iac(pty,IAC_DONT,value); } return -1; case IAC_DONT: return -1; case IAC_DO : if (value==3) { - send_iac(minor,IAC_WILL, 3); /* GO AHEAD*/ + send_iac(pty,IAC_WILL, 3); /* GO AHEAD*/ } else if (value==1) { - send_iac(minor,IAC_WILL, 1); /* ECHO */ + send_iac(pty,IAC_WILL, 1); /* ECHO */ } else { - send_iac(minor,IAC_WONT,value); + send_iac(pty,IAC_WONT,value); }; return -1; case IAC_WONT: if (value==1) { - send_iac(minor,IAC_WILL, 1); + send_iac(pty,IAC_WILL, 1); } else { /* ECHO */ - send_iac(minor,IAC_WONT,value); + send_iac(pty,IAC_WONT,value); } return -1; default: @@ -321,277 +303,75 @@ static int read_pty(int minor) 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 (minorc_cflag; - } else { - return -1; - }; - return 0; +static bool +ptySetAttributes(rtems_termios_device_context *base, const struct termios *t) +{ + rtems_pty_context *pty = (rtems_pty_context *)base; + pty->c_cflag = t->c_cflag; + return true; } /*-----------------------------------------------------------*/ -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 (minoriop->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 bool +ptyPollInitialize(rtems_termios_tty *ttyp, + rtems_termios_device_context *base, struct termios *t, + rtems_libio_open_close_args_t *args) +{ + rtems_pty_context *pty = (rtems_pty_context *)base; + pty->ttyp = ttyp; + pty->iac_mode = 0; + pty->sb_ind = 0; + pty->width = 0; + pty->height = 0; + return ptySetAttributes(&pty->base, t); } /*-----------------------------------------------------------*/ -static int -ptyShutdown(int major,int minor,void * arg) { - if (minor=0) close(telnet_ptys[minor].socket); - telnet_ptys[minor].socket=-1; - chown(telnet_ptys[minor].devname,2,0); - } else { - return -1; - } - return 0; +static void +ptyShutdown(rtems_termios_tty *ttyp, + rtems_termios_device_context *base, rtems_libio_open_close_args_t *arg) +{ + rtems_pty_context *pty = (rtems_pty_context *)base; + close(pty->socket); } /*-----------------------------------------------------------*/ /* Write Characters into pty device */ /*-----------------------------------------------------------*/ -static ssize_t -ptyPollWrite(int minor, const char * buf, size_t len) { - size_t count; - if (minor 0) { + ssize_t n = write(pty->socket, buf, len); + if (n <= 0) { + break; } - for (ndx=0;ndxbuffer; - pty_t *p = &telnet_ptys[minor]; - - switch (args->command) { + rtems_pty_context *p = (rtems_pty_context *)base; + struct winsize *wp = buffer; + switch (request) { 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; - + break; case TIOCSWINSZ: #if DEBUG & DEBUG_WH fprintf(stderr, @@ -602,61 +382,11 @@ rtems_device_driver my_pty_control( p->height = wp->ws_row; p->width = wp->ws_col; - args->ioctl_return=0; - - return RTEMS_SUCCESSFUL; - + break; 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"); + rtems_set_errno_and_return_minus_one(EINVAL); + break; } - return telnet_pty_inited; -} -int telnet_pty_initialize(void) -{ - return pty_do_initialize(); -} - -int telnet_pty_finalize(void) -{ - return pty_do_finalize(); + return 0; } diff --git a/cpukit/telnetd/telnetd.c b/cpukit/telnetd/telnetd.c index 43e00365b5..a661eb0088 100644 --- a/cpukit/telnetd/telnetd.c +++ b/cpukit/telnetd/telnetd.c @@ -64,14 +64,11 @@ #define PARANOIA -extern char *telnet_get_pty(int socket); -extern int telnet_pty_initialize(void); - struct shell_args { - char *devname; - void *arg; - char peername[16]; - char delete_myself; + rtems_pty_context pty; + void *arg; + char peername[16]; + char delete_myself; }; typedef union uni_sa { @@ -107,17 +104,23 @@ static const rtems_id (*telnetd_spawn_task)( void * ) = telnetd_dflt_spawn; -static char *grab_a_Connection( +static struct shell_args *grab_a_Connection( int des_socket, uni_sa *srv, char *peername, int sz ) { - char *rval = 0; + struct shell_args *args = NULL; socklen_t size_adr = sizeof(srv->sin); int acp_sock; + args = malloc(sizeof(*args)); + if (args == NULL) { + perror("telnetd:malloc"); + goto bailout; + } + acp_sock = accept(des_socket,&srv->sa,&size_adr); if (acp_sock<0) { @@ -125,7 +128,7 @@ static char *grab_a_Connection( goto bailout; }; - if ( !(rval=telnet_get_pty(acp_sock)) ) { + if (telnet_get_pty(&args->pty, acp_sock) == NULL) { syslog( LOG_DAEMON | LOG_ERR, "telnetd: unable to obtain PTY"); /* NOTE: failing 'do_get_pty()' closed the socket */ goto bailout; @@ -138,12 +141,12 @@ static char *grab_a_Connection( syslog(LOG_DAEMON | LOG_INFO, "telnetd: accepted connection from %s on %s", peername, - rval); + args->pty.name); #endif bailout: - return rval; + return args; } @@ -160,6 +163,7 @@ static void release_a_Connection(char *devname, char *peername, FILE **pstd, int while (--n>=0) if (pstd[n]) fclose(pstd[n]); + unlink(devname); } static int sockpeername(int sock, char *buf, int bufsz) @@ -186,7 +190,6 @@ rtems_task_telnetd(void *task_argument) { int des_socket; uni_sa srv; - char *devname; char peername[16]; int i=1; int size_adr; @@ -243,22 +246,19 @@ rtems_task_telnetd(void *task_argument) ); } } else { - devname = grab_a_Connection(des_socket, &srv, peername, sizeof(peername)); + arg = grab_a_Connection(des_socket, &srv, peername, sizeof(peername)); - if ( !devname ) { + if (arg == NULL) { /* if something went wrong, sleep for some time */ sleep(10); continue; } - arg = malloc( sizeof(*arg) ); - - arg->devname = devname; arg->arg = telnetd_config->arg; strncpy(arg->peername, peername, sizeof(arg->peername)); telnetd_task_id = telnetd_spawn_task( - devname, + arg->pty.name, telnetd_config->priority, telnetd_config->stack_size, spawned_shell, @@ -278,9 +278,9 @@ rtems_task_telnetd(void *task_argument) * a stream... */ - if ( !(dummy=fopen(devname,"r+")) ) + if ( !(dummy=fopen(arg->pty.name,"r+")) ) perror("Unable to dummy open the pty, losing a slot :-("); - release_a_Connection(devname, peername, &dummy, 1); + release_a_Connection(arg->pty.name, peername, &dummy, 1); free(arg); sleep(2); /* don't accept connections too fast */ } @@ -315,14 +315,6 @@ rtems_status_code rtems_telnetd_start(const rtems_telnetd_config_table* config) return RTEMS_NO_MEMORY; } - - if ( !telnet_pty_initialize() ) { - fprintf(stderr, "telnetd cannot initialize PTY driver\n"); - free(telnetd_config); - telnetd_config = NULL; - return RTEMS_IO_ERROR; - } - *telnetd_config = *config; /* Check priority */ @@ -396,7 +388,7 @@ spawned_shell(void *targ) /* redirect stdio */ for (i=0; i<3; i++) { - if ( !(nstd[i]=fopen(arg->devname,"r+")) ) { + if ( !(nstd[i]=fopen(arg->pty.name,"r+")) ) { perror("unable to open stdio"); goto cleanup; } @@ -418,13 +410,13 @@ spawned_shell(void *targ) start = rtems_shell_login_prompt( stdin, stderr, - arg->devname, + arg->pty.name, telnetd_config->login_check ); login_failed = !start; } if (start) { - telnetd_config->command( arg->devname, arg->arg); + telnetd_config->command( arg->pty.name, arg->arg); } stdin = ostd[0]; @@ -440,7 +432,7 @@ spawned_shell(void *targ) } cleanup: - release_a_Connection(arg->devname, arg->peername, nstd, i); + release_a_Connection(arg->pty.name, arg->peername, nstd, i); free(arg); } -- cgit v1.2.3