source: rtems/cpukit/telnetd/pty.c @ d3d2afdf

4.104.114.84.95
Last change on this file since d3d2afdf was d3d2afdf, checked in by Joel Sherrill <joel.sherrill@…>, on Oct 25, 2005 at 11:17:35 AM

2005-10-25 Joel Sherrill <joel@…>

  • sapi/include/confdefs.h, telnetd/pty.c, telnetd/pty.h: Attempt to fix MAX_PTYS and provide a real configuration entry. This should make telnetd some suitable for inclusion in cpukit.
  • Property mode set to 100644
File size: 10.4 KB
Line 
1/*
2 * /dev/ptyXX  (A first version for pseudo-terminals)
3 *
4 *  Author: Fernando RUIZ CASAS (fernando.ruiz@ctv.es)
5 *  May 2001
6 *
7 *  This program is distributed in the hope that it will be useful,
8 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
9 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 *
11 *  $Id$
12 */
13
14#ifdef HAVE_CONFIG_H
15#include "config.h"
16#endif
17
18/*-----------------------------------------*/
19#include <termios.h>
20#include <rtems.h>
21#include <rtems/libio.h>
22#include <rtems/pty.h>
23#include <rtems/bspIo.h>
24/*-----------------------------------------*/
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <unistd.h>
29/*-----------------------------------------*/
30#define IAC_ESC    255
31#define IAC_DONT   254
32#define IAC_DO     253
33#define IAC_WONT   252
34#define IAC_WILL   251
35#define IAC_SB     250
36#define IAC_GA     249
37#define IAC_EL     248
38#define IAC_EC     247
39#define IAC_AYT    246
40#define IAC_AO     245
41#define IAC_IP     244
42#define IAC_BRK    243
43#define IAC_DMARK  242
44#define IAC_NOP    241
45#define IAC_SE     240
46#define IAC_EOR    239
47
48typedef struct {
49 char                     *devname;
50 struct rtems_termios_tty *ttyp;
51 tcflag_t                  c_cflag;
52 int                       opened;
53 int                       socket;
54
55 int                       last_cr;
56 int                       iac_mode;   
57} pty_t;
58
59
60int ptys_initted=FALSE;
61pty_t *ptys;
62int rtems_telnetd_maximum_ptys;
63
64/* This procedure returns the devname for a pty slot free.
65 * If not slot availiable (field socket>=0)
66 *  then the socket argument is closed
67 */
68
69char *  get_pty(int socket) {
70        int ndx;
71        if (!ptys_initted) return NULL;
72        for (ndx=0;ndx<rtems_telnetd_maximum_ptys;ndx++) {
73                if (ptys[ndx].socket<0) {
74                        ptys[ndx].socket=socket;
75                        return ptys[ndx].devname;
76                };
77        };
78        close(socket);
79        return NULL;
80}
81
82
83/*-----------------------------------------------------------*/
84/*
85 * The NVT terminal is negociated in PollRead and PollWrite
86 * with every BYTE sendded or received.
87 * A litle status machine in the pty_read_byte(int minor)
88 *
89 */
90const char IAC_AYT_RSP[]="\r\nAYT? Yes, RTEMS-SHELL is here\r\n";
91const char IAC_BRK_RSP[]="<*Break*>";
92const char IAC_IP_RSP []="<*Interrupt*>";
93
94
95static
96int send_iac(int minor,unsigned char mode,unsigned char option) {
97        unsigned char buf[3];
98        buf[0]=IAC_ESC;
99        buf[1]=mode;
100        buf[2]=option;
101        return write(ptys[minor].socket,buf,sizeof(buf));
102}
103
104int read_pty(int minor) { /* Characters writed in the client side*/
105         unsigned char value;
106         int count;
107         int result;
108         count=read(ptys[minor].socket,&value,sizeof(value));
109         if (count<1) {
110          fclose(stdin);                 
111          fclose(stdout);               
112          fclose(stderr);               
113          /* If you don't read from the socket the system ends the task */
114          rtems_task_delete(RTEMS_SELF);
115         };
116         switch(ptys[minor].iac_mode) {
117          case IAC_ESC:
118               ptys[minor].iac_mode=0;
119               switch(value) {
120                case IAC_ESC :
121                     return IAC_ESC;
122                case IAC_DONT:
123                case IAC_DO  :
124                case IAC_WONT:
125                case IAC_WILL:
126                     ptys[minor].iac_mode=value;
127                     return -1;
128                case IAC_SB  :
129                     return -100;
130                case IAC_GA  :
131                     return -1;
132                case IAC_EL  :
133                     return 0x03; /* Ctrl-C*/
134                case IAC_EC  :
135                     return '\b';
136                case IAC_AYT :
137                     write(ptys[minor].socket,IAC_AYT_RSP,strlen(IAC_AYT_RSP));
138                     return -1;
139                case IAC_AO  :
140                     return -1;
141                case IAC_IP  :
142                     write(ptys[minor].socket,IAC_IP_RSP,strlen(IAC_IP_RSP));
143                     return -1;
144                case IAC_BRK :
145                     write(ptys[minor].socket,IAC_BRK_RSP,strlen(IAC_BRK_RSP));
146                     return -1;
147                case IAC_DMARK:
148                     return -2;
149                case IAC_NOP :
150                     return -1;
151                case IAC_SE  :
152                     return -101;
153                case IAC_EOR :
154                     return -102;
155                default      :
156                     return -1;
157               };
158               break;
159          case IAC_WILL:
160               ptys[minor].iac_mode=0;
161               if (value==34){send_iac(minor,IAC_DONT,   34);       /*LINEMODE*/ 
162                              send_iac(minor,IAC_DO  ,    1);} else /*ECHO    */
163                             {send_iac(minor,IAC_DONT,value);};
164               return -1;
165          case IAC_DONT:
166               ptys[minor].iac_mode=0;
167               return -1;
168          case IAC_DO  :
169               ptys[minor].iac_mode=0;
170               if (value==3) {send_iac(minor,IAC_WILL,    3);} else /* GO AHEAD*/
171               if (value==1) {                               } else /* ECHO */
172                             {send_iac(minor,IAC_WONT,value);};
173               return -1;
174          case IAC_WONT:
175               ptys[minor].iac_mode=0;
176               if (value==1) {send_iac(minor,IAC_WILL,    1);} else /* ECHO */
177                             {send_iac(minor,IAC_WONT,value);};
178               return -1;
179          default:
180               ptys[minor].iac_mode=0;
181               if (value==IAC_ESC) {
182                     ptys[minor].iac_mode=value;
183                     return -1;
184               } else {
185                     result=value; 
186                     if ((value=='\n') && (ptys[minor].last_cr)) result=-1;
187                     ptys[minor].last_cr=(value=='\r');
188                     return result;
189               };
190         };
191       
192}
193
194/*-----------------------------------------------------------*/
195static int ptySetAttributes(int minor,const struct termios *t);
196static int ptyPollInitialize(int major,int minor,void * arg) ;
197static int ptyShutdown(int major,int minor,void * arg) ;
198static int ptyPollWrite(int minor, const char * buf,int len) ;
199static int ptyPollRead(int minor) ;
200const rtems_termios_callbacks * pty_get_termios_handlers(int polled) ;
201/*-----------------------------------------------------------*/
202/* Set the 'Hardware'                                        */ 
203/*-----------------------------------------------------------*/
204static int
205ptySetAttributes(int minor,const struct termios *t) {
206        if (minor<rtems_telnetd_maximum_ptys) { 
207         ptys[minor].c_cflag=t->c_cflag;       
208        } else {
209         return -1;
210        };
211        return 0;
212}
213/*-----------------------------------------------------------*/
214static int 
215ptyPollInitialize(int major,int minor,void * arg) {
216        rtems_libio_open_close_args_t * args = arg;
217        struct termios t;
218        if (minor<rtems_telnetd_maximum_ptys) { 
219         if (ptys[minor].socket<0) return -1;           
220         ptys[minor].opened=TRUE;
221         ptys[minor].ttyp=args->iop->data1;
222         t.c_cflag=B9600|CS8;/* termios default */
223         return ptySetAttributes(minor,&t);
224        } else {
225         return -1;
226        };
227}
228/*-----------------------------------------------------------*/
229static int 
230ptyShutdown(int major,int minor,void * arg) {
231        if (minor<rtems_telnetd_maximum_ptys) { 
232         ptys[minor].opened=FALSE;
233         if (ptys[minor].socket>=0) close(ptys[minor].socket);
234         ptys[minor].socket=-1;
235         chown(ptys[minor].devname,2,0);
236        } else {
237         return -1;
238        };
239        return 0;
240}
241/*-----------------------------------------------------------*/
242/* Write Characters into pty device                          */ 
243/*-----------------------------------------------------------*/
244static int
245ptyPollWrite(int minor, const char * buf,int len) {
246        int count;
247        if (minor<rtems_telnetd_maximum_ptys) { 
248         if (ptys[minor].socket<0) return -1;           
249         count=write(ptys[minor].socket,buf,len);
250        } else {
251         count=-1;
252        };
253        return count;
254}
255/*-----------------------------------------------------------*/
256static int
257ptyPollRead(int minor) {
258        int result;
259        if (minor<rtems_telnetd_maximum_ptys) { 
260         if (ptys[minor].socket<0) return -1;           
261         result=read_pty(minor);
262         return result;
263        };
264        return -1;
265}
266/*-----------------------------------------------------------*/
267static const rtems_termios_callbacks pty_poll_callbacks = {
268        ptyPollInitialize,      /* FirstOpen*/
269        ptyShutdown,            /* LastClose*/
270        ptyPollRead,            /* PollRead  */
271        ptyPollWrite,           /* Write */
272        ptySetAttributes,       /* setAttributes */
273        NULL,                   /* stopRemoteTX */
274        NULL,                   /* StartRemoteTX */
275        0                       /* outputUsesInterrupts */
276};
277/*-----------------------------------------------------------*/
278const rtems_termios_callbacks * pty_get_termios_handlers(int polled) {
279        return &pty_poll_callbacks;
280}
281/*-----------------------------------------------------------*/
282void init_ptys(void) {
283        int ndx;
284        ptys = malloc( sizeof(pty_t) * rtems_telnetd_maximum_ptys );
285        for (ndx=0;ndx<rtems_telnetd_maximum_ptys;ndx++) {
286                ptys[ndx].devname=malloc(strlen("/dev/ptyXX")+1);
287                sprintf(ptys[ndx].devname,"/dev/pty%X",ndx);
288                ptys[ndx].ttyp=NULL;
289                ptys[ndx].c_cflag=CS8|B9600;
290                ptys[ndx].socket=-1;
291                ptys[ndx].opened=FALSE;
292
293        };
294        ptys_initted=TRUE;
295}
296
297
298/*-----------------------------------------------------------*/
299/*  pty_initialize
300 *
301 *  This routine initializes the pty IO driver.
302 *
303 *  Input parameters: NONE
304 *
305 *  Output parameters:  NONE
306 *
307 *  Return values:
308 */
309/*-----------------------------------------------------------*/
310rtems_device_driver pty_initialize(
311  rtems_device_major_number  major,
312  rtems_device_minor_number  minor,
313  void                      *arg
314)
315{
316  int ndx;     
317  rtems_status_code status;
318
319  /*
320   * Set up ptys
321   */
322
323  init_ptys();
324
325  /*
326   * Register the devices
327   */
328  for (ndx=0;ndx<rtems_telnetd_maximum_ptys;ndx++) {
329   status = rtems_io_register_name(ptys[ndx].devname, major, ndx);
330   if (status != RTEMS_SUCCESSFUL)
331     rtems_fatal_error_occurred(status);
332   chmod(ptys[ndx].devname,0660);
333   chown(ptys[ndx].devname,2,0); /* tty,root*/
334  };
335  printk("Device: /dev/pty%X../dev/pty%X (%d)pseudo-terminals registered.\n",
336      0,rtems_telnetd_maximum_ptys-1,rtems_telnetd_maximum_ptys);
337
338  return RTEMS_SUCCESSFUL;
339}
340
341
342/*
343 *  Open entry point
344 */
345
346rtems_device_driver pty_open(
347  rtems_device_major_number major,
348  rtems_device_minor_number minor,
349  void                    * arg
350)
351{
352  rtems_status_code sc ;
353  sc = rtems_termios_open(major,minor,arg,pty_get_termios_handlers(FALSE));
354  return sc;
355}
356 
357/*
358 *  Close entry point
359 */
360
361rtems_device_driver pty_close(
362  rtems_device_major_number major,
363  rtems_device_minor_number minor,
364  void                    * arg
365)
366{
367  return rtems_termios_close(arg);
368}
369
370/*
371 * read bytes from the pty
372 */
373
374rtems_device_driver pty_read(
375  rtems_device_major_number major,
376  rtems_device_minor_number minor,
377  void                    * arg
378)
379{
380  return rtems_termios_read(arg);
381}
382
383/*
384 * write bytes to the pty
385 */
386
387rtems_device_driver pty_write(
388  rtems_device_major_number major,
389  rtems_device_minor_number minor,
390  void                    * arg
391)
392{
393  return rtems_termios_write(arg);
394}
395
396/*
397 *  IO Control entry point
398 */
399
400rtems_device_driver pty_control(
401  rtems_device_major_number major,
402  rtems_device_minor_number minor,
403  void                    * arg
404)
405{
406  return rtems_termios_ioctl(arg);
407}
Note: See TracBrowser for help on using the repository browser.