File indexing completed on 2025-05-11 08:24:27
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025 #ifdef HAVE_CONFIG_H
0026 #include "config.h"
0027 #endif
0028
0029 #define DEBUG_WH (1<<0)
0030 #define DEBUG_DETAIL (1<<1)
0031
0032
0033
0034
0035 #include <sys/ttycom.h>
0036 #include <rtems/pty.h>
0037 #include <rtems/seterr.h>
0038 #include <errno.h>
0039 #include <sys/socket.h>
0040
0041 #include <inttypes.h>
0042 #include <stdio.h>
0043 #include <stdlib.h>
0044 #include <string.h>
0045 #include <syslog.h>
0046 #include <unistd.h>
0047
0048 #define IAC_ESC 255
0049 #define IAC_DONT 254
0050 #define IAC_DO 253
0051 #define IAC_WONT 252
0052 #define IAC_WILL 251
0053 #define IAC_SB 250
0054 #define IAC_GA 249
0055 #define IAC_EL 248
0056 #define IAC_EC 247
0057 #define IAC_AYT 246
0058 #define IAC_AO 245
0059 #define IAC_IP 244
0060 #define IAC_BRK 243
0061 #define IAC_DMARK 242
0062 #define IAC_NOP 241
0063 #define IAC_SE 240
0064 #define IAC_EOR 239
0065
0066 #define SB_MAX RTEMS_PTY_SB_MAX
0067
0068 static bool ptyPollInitialize(rtems_termios_tty *,
0069 rtems_termios_device_context *, struct termios *,
0070 rtems_libio_open_close_args_t *);
0071 static void ptyShutdown(rtems_termios_tty *,
0072 rtems_termios_device_context *, rtems_libio_open_close_args_t *);
0073 static void ptyPollWrite(rtems_termios_device_context *, const char *, size_t);
0074 static int ptyPollRead(rtems_termios_device_context *);
0075 static bool ptySetAttributes(rtems_termios_device_context *,
0076 const struct termios *);
0077 static int my_pty_control(rtems_termios_device_context *,
0078 ioctl_command_t, void *);
0079
0080 static const rtems_termios_device_handler pty_handler = {
0081 .first_open = ptyPollInitialize,
0082 .last_close = ptyShutdown,
0083 .poll_read = ptyPollRead,
0084 .write = ptyPollWrite,
0085 .set_attributes = ptySetAttributes,
0086 .ioctl = my_pty_control
0087 };
0088
0089 static
0090 int send_iac(rtems_pty_context *pty, unsigned char mode, unsigned char option)
0091 {
0092 unsigned char buf[3];
0093
0094 buf[0]=IAC_ESC;
0095 buf[1]=mode;
0096 buf[2]=option;
0097 return write(pty->socket, buf, sizeof(buf));
0098 }
0099
0100 const char *rtems_pty_initialize(rtems_pty_context *pty, uintptr_t unique)
0101 {
0102 rtems_status_code sc;
0103
0104 memset(pty, 0, sizeof(*pty));
0105 (void)snprintf(pty->name, sizeof(pty->name), "/dev/pty%" PRIuPTR, unique);
0106 rtems_termios_device_context_initialize(&pty->base, "pty");
0107 pty->socket = -1;
0108 sc = rtems_termios_device_install(pty->name, &pty_handler, NULL, &pty->base);
0109 if (sc != RTEMS_SUCCESSFUL) {
0110 return NULL;
0111 }
0112
0113 return pty->name;
0114 }
0115
0116 void rtems_pty_close_socket(rtems_pty_context *pty)
0117 {
0118 if (pty->socket >= 0) {
0119 (void)close(pty->socket);
0120 pty->socket = -1;
0121 }
0122 }
0123
0124 void rtems_pty_set_socket(rtems_pty_context *pty, int socket)
0125 {
0126 struct timeval t;
0127
0128 rtems_pty_close_socket(pty);
0129 pty->socket = socket;
0130
0131
0132 t.tv_sec=2;
0133 t.tv_usec=00000;
0134 (void)setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(t));
0135
0136
0137 send_iac(pty, IAC_WILL, 1);
0138 }
0139
0140
0141
0142
0143
0144
0145
0146
0147 static const char IAC_AYT_RSP[]="\r\nAYT? Yes, RTEMS-SHELL is here\r\n";
0148 static const char IAC_BRK_RSP[]="<*Break*>";
0149 static const char IAC_IP_RSP []="<*Interrupt*>";
0150
0151 static int
0152 handleSB(rtems_pty_context *pty)
0153 {
0154 switch (pty->sb_buf[0]) {
0155 case 31:
0156 pty->width = (pty->sb_buf[1]<<8) + pty->sb_buf[2];
0157 pty->height = (pty->sb_buf[3]<<8) + pty->sb_buf[4];
0158 #if DEBUG & DEBUG_WH
0159 fprintf(stderr,
0160 "Setting width/height to %ix%i\n",
0161 pty->width,
0162 pty->height);
0163 #endif
0164 break;
0165 default:
0166 break;
0167 }
0168 return 0;
0169 }
0170
0171 static int ptyPollRead(rtems_termios_device_context *base)
0172 {
0173 rtems_pty_context *pty = (rtems_pty_context *)base;
0174 unsigned char value;
0175 unsigned int omod;
0176 int count;
0177 int result;
0178
0179 count=read(pty->socket,&value,sizeof(value));
0180 if (count<0)
0181 return -1;
0182
0183 if (count<1) {
0184
0185
0186
0187
0188
0189
0190
0191 pty->ttyp->cindex=pty->ttyp->ccount+1;
0192 return pty->ttyp->termios.c_cc[VEOF];
0193 };
0194
0195 omod=pty->iac_mode;
0196 pty->iac_mode=0;
0197 switch(omod & 0xff) {
0198 case IAC_ESC:
0199 switch(value) {
0200 case IAC_ESC :
0201
0202 pty->iac_mode = omod>>8;
0203 return IAC_ESC;
0204 case IAC_DONT:
0205 case IAC_DO :
0206 case IAC_WONT:
0207 case IAC_WILL:
0208 pty->iac_mode=value;
0209 return -1;
0210 case IAC_SB :
0211 #if DEBUG & DEBUG_DETAIL
0212 printk("SB\n");
0213 #endif
0214 pty->iac_mode=value;
0215 pty->sb_ind=0;
0216 return -100;
0217 case IAC_GA :
0218 return -1;
0219 case IAC_EL :
0220 return 0x03;
0221 case IAC_EC :
0222 return '\b';
0223 case IAC_AYT :
0224 write(pty->socket,IAC_AYT_RSP,strlen(IAC_AYT_RSP));
0225 return -1;
0226 case IAC_AO :
0227 return -1;
0228 case IAC_IP :
0229 write(pty->socket,IAC_IP_RSP,strlen(IAC_IP_RSP));
0230 return -1;
0231 case IAC_BRK :
0232 write(pty->socket,IAC_BRK_RSP,strlen(IAC_BRK_RSP));
0233 return -1;
0234 case IAC_DMARK:
0235 return -2;
0236 case IAC_NOP :
0237 return -1;
0238 case IAC_SE :
0239 #if DEBUG & DEBUG_DETAIL
0240 {
0241 int i;
0242 printk("SE");
0243 for (i=0; i<pty->sb_ind; i++)
0244 printk(" %02x",pty->sb_buf[i]);
0245 printk("\n");
0246 }
0247 #endif
0248 handleSB(pty);
0249 return -101;
0250 case IAC_EOR :
0251 return -102;
0252 default :
0253 return -1;
0254 };
0255 break;
0256
0257 case IAC_SB:
0258 pty->iac_mode=omod;
0259 if (IAC_ESC==value) {
0260 pty->iac_mode=(omod<<8)|value;
0261 } else {
0262 if (pty->sb_ind < SB_MAX)
0263 pty->sb_buf[pty->sb_ind++]=value;
0264 }
0265 return -1;
0266
0267 case IAC_WILL:
0268 if (value==34){
0269 send_iac(pty,IAC_DONT, 34);
0270 send_iac(pty,IAC_DO , 1);
0271 } else if (value==31) {
0272 send_iac(pty,IAC_DO , 31);
0273 #if DEBUG & DEBUG_DETAIL
0274 printk("replied DO NAWS\n");
0275 #endif
0276 } else {
0277 send_iac(pty,IAC_DONT,value);
0278 }
0279 return -1;
0280 case IAC_DONT:
0281 return -1;
0282 case IAC_DO :
0283 if (value==3) {
0284 send_iac(pty,IAC_WILL, 3);
0285 } else if (value==1) {
0286 send_iac(pty,IAC_WILL, 1);
0287 } else {
0288 send_iac(pty,IAC_WONT,value);
0289 };
0290 return -1;
0291 case IAC_WONT:
0292 if (value==1) {
0293 send_iac(pty,IAC_WILL, 1);
0294 } else {
0295 send_iac(pty,IAC_WONT,value);
0296 }
0297 return -1;
0298 default:
0299 if (value==IAC_ESC) {
0300 pty->iac_mode=value;
0301 return -1;
0302 } else {
0303 result=value;
0304 if ( 0
0305
0306 || ((value=='\n') && pty->last_cr)
0307
0308 || ((value==0) && pty->last_cr)
0309 ) result=-1;
0310 pty->last_cr=(value=='\r');
0311 return result;
0312 };
0313 };
0314
0315 return -1;
0316 }
0317
0318
0319
0320
0321 static bool
0322 ptySetAttributes(rtems_termios_device_context *base, const struct termios *t)
0323 {
0324 rtems_pty_context *pty = (rtems_pty_context *)base;
0325 pty->c_cflag = t->c_cflag;
0326 return true;
0327 }
0328
0329 static bool
0330 ptyPollInitialize(rtems_termios_tty *ttyp,
0331 rtems_termios_device_context *base, struct termios *t,
0332 rtems_libio_open_close_args_t *args)
0333 {
0334 rtems_pty_context *pty = (rtems_pty_context *)base;
0335 pty->ttyp = ttyp;
0336 pty->iac_mode = 0;
0337 pty->sb_ind = 0;
0338 pty->width = 0;
0339 pty->height = 0;
0340 return ptySetAttributes(&pty->base, t);
0341 }
0342
0343 static void
0344 ptyShutdown(rtems_termios_tty *ttyp,
0345 rtems_termios_device_context *base, rtems_libio_open_close_args_t *arg)
0346 {
0347 rtems_pty_context *pty = (rtems_pty_context *)base;
0348 close(pty->socket);
0349 }
0350
0351
0352
0353 static void
0354 ptyPollWrite(rtems_termios_device_context *base, const char *buf, size_t len)
0355 {
0356 rtems_pty_context *pty = (rtems_pty_context *)base;
0357
0358 while (len > 0) {
0359 ssize_t n = write(pty->socket, buf, len);
0360 if (n <= 0) {
0361 break;
0362 }
0363
0364 buf += (size_t)n;
0365 len -= (size_t)n;
0366 }
0367 }
0368
0369 static int
0370 my_pty_control(rtems_termios_device_context *base,
0371 ioctl_command_t request, void *buffer)
0372 {
0373 rtems_pty_context *p = (rtems_pty_context *)base;
0374 struct winsize *wp = buffer;
0375
0376 switch (request) {
0377 case TIOCGWINSZ:
0378 wp->ws_row = p->height;
0379 wp->ws_col = p->width;
0380 #if DEBUG & DEBUG_WH
0381 fprintf(stderr,
0382 "ioctl(TIOCGWINSZ), returning %ix%i\n",
0383 wp->ws_col,
0384 wp->ws_row);
0385 #endif
0386 break;
0387 case TIOCSWINSZ:
0388 #if DEBUG & DEBUG_WH
0389 fprintf(stderr,
0390 "ioctl(TIOCGWINSZ), setting %ix%i\n",
0391 wp->ws_col,
0392 wp->ws_row);
0393 #endif
0394
0395 p->height = wp->ws_row;
0396 p->width = wp->ws_col;
0397 break;
0398 default:
0399 rtems_set_errno_and_return_minus_one(EINVAL);
0400 break;
0401 }
0402
0403 return 0;
0404 }