static int open_pty_slave(char *name) { int sfd; struct termios tty_rmode; if ((sfd = sf_open(name, O_RDWR, 0)) < 0) { return -1; } #if defined(__sun) && defined(__SVR4) /* Load the necessary STREAMS modules for Solaris */ if ((ioctl(sfd, I_FIND, "ldterm")) < 0) { ERROR0(LOG_ERR, "Failed to find ldterm STREAMS module"); return -1; } if (ioctl(sfd, I_PUSH, "ptem") < 0) { ERROR0(LOG_ERR, "Failed to push ptem STREAMS module"); return -1; } if (ioctl(sfd, I_PUSH, "ldterm") < 0) { ERROR0(LOG_ERR, "Failed to push ldterm STREAMS module"); return -1; } if (ioctl(sfd, I_PUSH, "ttcompat") < 0) { ERROR0(LOG_ERR, "Failed to push ttcompat STREAMS module"); return -1; } #endif if (getenv("RUN_ERL_DISABLE_FLOWCNTRL")) { if (tcgetattr(sfd, &tty_rmode) < 0) { fprintf(stderr, "Cannot get terminal's current mode\n"); exit(-1); } tty_rmode.c_iflag &= ~IXOFF; if (tcsetattr(sfd, TCSANOW, &tty_rmode) < 0) { fprintf(stderr, "Cannot disable terminal's flow control on input\n"); exit(-1); } tty_rmode.c_iflag &= ~IXON; if (tcsetattr(sfd, TCSANOW, &tty_rmode) < 0) { fprintf(stderr, "Cannot disable terminal's flow control on output\n"); exit(-1); } } #ifdef DEBUG if (tcgetattr(sfd, &tty_rmode) < 0) { fprintf(stderr, "Cannot get terminals current mode\n"); exit(-1); } show_terminal_settings(&tty_rmode); #endif return sfd; }
static int open_pty_master(char **ptyslave, int *sfdp) { int mfd; /* Use the posix_openpt if working, as this guarantees creation of the slave device properly. */ #if defined(HAVE_WORKING_POSIX_OPENPT) || (defined(__sun) && defined(__SVR4)) # ifdef HAVE_WORKING_POSIX_OPENPT if ((mfd = posix_openpt(O_RDWR)) >= 0) { # elif defined(__sun) && defined(__SVR4) mfd = sf_open("/dev/ptmx", O_RDWR, 0); if (mfd >= 0) { # endif if ((*ptyslave = ptsname(mfd)) != NULL && grantpt(mfd) == 0 && unlockpt(mfd) == 0) { return mfd; } sf_close(mfd); } /* fallback to openpty if it exist */ #endif #if defined(HAVE_OPENPTY) # ifdef PATH_MAX # define SLAVE_SIZE PATH_MAX # else # define SLAVE_SIZE 1024 # endif { static char slave[SLAVE_SIZE]; # undef SLAVE_SIZE if (openpty(&mfd, sfdp, slave, NULL, NULL) == 0) { *ptyslave = slave; return mfd; } } #elif !defined(HAVE_WORKING_POSIX_OPENPT) /* * The traditional way to find ptys. We only try it if neither * posix_openpt or openpty() are available. */ char *major, *minor; static char majorchars[] = "pqrstuvwxyzabcdePQRSTUVWXYZABCDE"; static char minorchars[] = "0123456789abcdefghijklmnopqrstuv" "wxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_+"; /* In the old time the names where /dex/ptyXY where */ /* X is in "pqrs" and Y in "0123456789abcdef" but FreeBSD */ /* and some Linux version has extended this. */ /* This code could probebly be improved alot. For example look at */ /* http://www.xcf.berkeley.edu/~ali/K0D/UNIX/PTY/code/pty.c.html */ /* http://www.xcf.berkeley.edu/~ali/K0D/UNIX/PTY/code/upty.h.html */ { /* New style devpts or devfs /dev/pty/{m,s}{0,1....} */ static char ptyname[] = "/dev/pty/mX"; for (minor = minorchars; *minor; minor++) { ptyname[10] = *minor; if ((mfd = sf_open(ptyname, O_RDWR, 0)) >= 0) { ptyname[9] = 's'; *ptyslave = ptyname; return mfd; } } } { /* Unix98 style /dev/ptym/ptyXY and /dev/pty/ttyXY */ static char ptyname[] = "/dev/ptym/ptyXY"; static char ttyname[] = "/dev/pty/ttyXY"; for (major = majorchars; *major; major++) { ptyname[13] = *major; for (minor = minorchars; *minor; minor++) { ptyname[14] = *minor; if ((mfd = sf_open(ptyname, O_RDWR, 0)) >= 0) { ttyname[12] = *major; ttyname[13] = *minor; *ptyslave = ttyname; return mfd; } } } } { /* Old style /dev/ptyXY */ static char ptyname[] = "/dev/ptyXY"; for (major = majorchars; *major; major++) { ptyname[8] = *major; for (minor = minorchars; *minor; minor++) { ptyname[9] = *minor; if ((mfd = sf_open(ptyname, O_RDWR, 0)) >= 0) { ptyname[5] = 't'; *ptyslave = ptyname; return mfd; } } } } #endif /* !HAVE_OPENPTY */ return -1; } static int open_pty_slave(char *name) { int sfd; struct termios tty_rmode; if ((sfd = sf_open(name, O_RDWR, 0)) < 0) { return -1; } #if defined(__sun) && defined(__SVR4) /* Load the necessary STREAMS modules for Solaris */ if ((ioctl(sfd, I_FIND, "ldterm")) < 0) { ERROR0(LOG_ERR, "Failed to find ldterm STREAMS module"); return -1; } if (ioctl(sfd, I_PUSH, "ptem") < 0) { ERROR0(LOG_ERR, "Failed to push ptem STREAMS module"); return -1; } if (ioctl(sfd, I_PUSH, "ldterm") < 0) { ERROR0(LOG_ERR, "Failed to push ldterm STREAMS module"); return -1; } if (ioctl(sfd, I_PUSH, "ttcompat") < 0) { ERROR0(LOG_ERR, "Failed to push ttcompat STREAMS module"); return -1; } #endif if (getenv("RUN_ERL_DISABLE_FLOWCNTRL")) { if (tcgetattr(sfd, &tty_rmode) < 0) { fprintf(stderr, "Cannot get terminal's current mode\n"); exit(-1); } tty_rmode.c_iflag &= ~IXOFF; if (tcsetattr(sfd, TCSANOW, &tty_rmode) < 0) { fprintf(stderr, "Cannot disable terminal's flow control on input\n"); exit(-1); } tty_rmode.c_iflag &= ~IXON; if (tcsetattr(sfd, TCSANOW, &tty_rmode) < 0) { fprintf(stderr, "Cannot disable terminal's flow control on output\n"); exit(-1); } } #ifdef DEBUG if (tcgetattr(sfd, &tty_rmode) < 0) { fprintf(stderr, "Cannot get terminals current mode\n"); exit(-1); } show_terminal_settings(&tty_rmode); #endif return sfd; }
int main(int argc, char **argv) { char FIFO1[FILENAME_MAX], FIFO2[FILENAME_MAX]; int i, len, wfd, rfd; fd_set readfds; char buf[BUFSIZ]; char pipename[FILENAME_MAX]; int pipeIx = 1; int force_lock = 0; int got_some = 0; if (argc >= 2 && argv[1][0]=='-') { switch (argv[1][1]) { case 'h': usage(argv[0]); exit(1); case 'F': force_lock = 1; break; default: fprintf(stderr,"Invalid option '%s'\n",argv[1]); exit(1); } pipeIx = 2; } #ifdef DEBUG fprintf(stderr, "%s: pid is : %d\n", argv[0], (int)getpid()); #endif strn_cpy(pipename, sizeof(pipename), (argv[pipeIx] ? argv[pipeIx] : PIPE_DIR)); if(*pipename && pipename[strlen(pipename)-1] == '/') { /* The user wishes us to find a pipe name in the specified */ /* directory */ int highest_pipe_num = 0; DIR *dirp; struct dirent *direntp; dirp = opendir(pipename); if(!dirp) { fprintf(stderr, "Can't access pipe directory %s: %s\n", pipename, strerror(errno)); exit(1); } /* Check the directory for existing pipes */ while((direntp=readdir(dirp)) != NULL) { if(strncmp(direntp->d_name,PIPE_STUBNAME,PIPE_STUBLEN)==0) { int num = atoi(direntp->d_name+PIPE_STUBLEN+1); if(num > highest_pipe_num) highest_pipe_num = num; } } closedir(dirp); strn_catf(pipename, sizeof(pipename), (highest_pipe_num?"%s.%d":"%s"), PIPE_STUBNAME, highest_pipe_num); } /* if */ /* read FIFO */ sn_printf(FIFO1,sizeof(FIFO1),"%s.r",pipename); /* write FIFO */ sn_printf(FIFO2,sizeof(FIFO2),"%s.w",pipename); /* Check that nobody is running to_erl on this pipe already */ if ((wfd = open (FIFO1, O_WRONLY|DONT_BLOCK_PLEASE, 0)) >= 0) { /* Open as server succeeded -- to_erl is already running! */ close(wfd); fprintf(stderr, "Another to_erl process already attached to pipe " "%s.\n", pipename); if (force_lock) { fprintf(stderr, "But we proceed anyway by force (-F).\n"); } else { exit(1); } } if ((rfd = open (FIFO1, O_RDONLY|DONT_BLOCK_PLEASE, 0)) < 0) { #ifdef DEBUG fprintf(stderr, "Could not open FIFO %s for reading.\n", FIFO1); #endif fprintf(stderr, "No running Erlang on pipe %s: %s\n", pipename, strerror(errno)); exit(1); } #ifdef DEBUG fprintf(stderr, "to_erl: %s opened for reading\n", FIFO1); #endif if ((wfd = open (FIFO2, O_WRONLY|DONT_BLOCK_PLEASE, 0)) < 0) { #ifdef DEBUG fprintf(stderr, "Could not open FIFO %s for writing.\n", FIFO2); #endif fprintf(stderr, "No running Erlang on pipe %s: %s\n", pipename, strerror(errno)); close(rfd); exit(1); } #ifdef DEBUG fprintf(stderr, "to_erl: %s opened for writing\n", FIFO2); #endif fprintf(stderr, "Attaching to %s (^D to exit)\n\n", pipename); /* Set break handler to our handler */ signal(SIGINT,handle_ctrlc); /* * Save the current state of the terminal, and set raw mode. */ if (tcgetattr(0, &tty_rmode) , 0) { fprintf(stderr, "Cannot get terminals current mode\n"); exit(-1); } tty_smode = tty_rmode; tty_eof = '\004'; /* Ctrl+D to exit */ #ifdef DEBUG show_terminal_settings(&tty_rmode); #endif tty_smode.c_iflag = 1*BRKINT |/*Signal interrupt on break.*/ 1*IGNPAR |/*Ignore characters with parity errors.*/ 1*ISTRIP |/*Strip character.*/ 0; #if 0 0*IGNBRK |/*Ignore break condition.*/ 0*PARMRK |/*Mark parity errors.*/ 0*INPCK |/*Enable input parity check.*/ 0*INLCR |/*Map NL to CR on input.*/ 0*IGNCR |/*Ignore CR.*/ 0*ICRNL |/*Map CR to NL on input.*/ 0*IUCLC |/*Map upper-case to lower-case on input.*/ 0*IXON |/*Enable start/stop output control.*/ 0*IXANY |/*Enable any character to restart output.*/ 0*IXOFF |/*Enable start/stop input control.*/ 0*IMAXBEL|/*Echo BEL on input line too long.*/ #endif tty_smode.c_oflag = 1*OPOST |/*Post-process output.*/ 1*ONLCR |/*Map NL to CR-NL on output.*/ #ifdef XTABS 1*XTABS |/*Expand tabs to spaces. (Linux)*/ #endif #ifdef OXTABS 1*OXTABS |/*Expand tabs to spaces. (FreeBSD)*/ #endif #ifdef NL0 1*NL0 |/*Select newline delays*/ #endif #ifdef CR0 1*CR0 |/*Select carriage-return delays*/ #endif #ifdef TAB0 1*TAB0 |/*Select horizontal tab delays*/ #endif #ifdef BS0 1*BS0 |/*Select backspace delays*/ #endif #ifdef VT0 1*VT0 |/*Select vertical tab delays*/ #endif #ifdef FF0 1*FF0 |/*Select form feed delays*/ #endif 0; #if 0 0*OLCUC |/*Map lower case to upper on output.*/ 0*OCRNL |/*Map CR to NL on output.*/ 0*ONOCR |/*No CR output at column 0.*/ 0*ONLRET |/*NL performs CR function.*/ 0*OFILL |/*Use fill characters for delay.*/ 0*OFDEL |/*Fill is DEL, else NULL.*/ 0*NL1 | 0*CR1 | 0*CR2 | 0*CR3 | 0*TAB1 | 0*TAB2 | 0*TAB3 |/*Expand tabs to spaces.*/ 0*BS1 | 0*VT1 | 0*FF1 | #endif /* JALI: removed setting the tty_smode.c_cflag flags, since this is not */ /* advisable if this is a *real* terminal, such as the console. In fact */ /* this may hang the entire machine, deep, deep down (signalling break */ /* or toggling the abort switch doesn't help) */ tty_smode.c_lflag = 0; #if 0 0*ISIG |/*Enable signals.*/ 0*ICANON |/*Canonical input (erase and kill processing).*/ 0*XCASE |/*Canonical upper/lower presentation.*/ 0*ECHO |/*Enable echo.*/ 0*ECHOE |/*Echo erase character as BS-SP-BS.*/ 0*ECHOK |/*Echo NL after kill character.*/ 0*ECHONL |/*Echo NL.*/ 0*NOFLSH |/*Disable flush after interrupt or quit.*/ 0*TOSTOP |/*Send SIGTTOU for background output.*/ 0*ECHOCTL|/*Echo control characters as ^char, delete as ^?.*/ 0*ECHOPRT|/*Echo erase character as character erased.*/ 0*ECHOKE |/*BS-SP-BS erase entire line on line kill.*/ 0*FLUSHO |/*Output is being flushed.*/ 0*PENDIN |/*Retype pending input at next read or input character.*/ 0*IEXTEN |/*Enable extended (implementation-defined) functions.*/ #endif tty_smode.c_cc[VMIN] =0;/* Note that VMIN is the same as VEOF! */ tty_smode.c_cc[VTIME] =0;/* Note that VTIME is the same as VEOL! */ tty_smode.c_cc[VINTR] =3; tcsetattr(0, TCSANOW, &tty_smode); #ifdef DEBUG show_terminal_settings(&tty_smode); #endif /* * "Write a ^R to the FIFO which causes the other end to redisplay * the input line." * This does not seem to work as was intended in old comment above. * However, this control character is now (R12B-3) used by run_erl * to trigger the version handshaking between to_erl and run_erl * at the start of every new to_erl-session. */ if (write(wfd, "\014", 1) < 0) { fprintf(stderr, "Error in writing ^R to FIFO.\n"); } /* * read and write */ while (1) { FD_ZERO(&readfds); FD_SET(0, &readfds); FD_SET(rfd, &readfds); if (select(rfd + 1, &readfds, NULL, NULL, NULL) < 0) { if (recv_sig) { FD_ZERO(&readfds); } else { fprintf(stderr, "Error in select.\n"); break; } } len = 0; /* * Read from terminal and write to FIFO */ if (recv_sig) { switch (recv_sig) { case SIGINT: fprintf(stderr, "[Break]\n\r"); buf[0] = '\003'; len = 1; break; case SIGWINCH: len = window_size_seq(buf,sizeof(buf)); break; default: fprintf(stderr,"Unexpected signal: %u\n",recv_sig); } recv_sig = 0; } else if (FD_ISSET(0, &readfds)) { len = read(0, buf, sizeof(buf)); if (len <= 0) { close(rfd); close(wfd); if (len < 0) { fprintf(stderr, "Error in reading from stdin.\n"); } else { fprintf(stderr, "[EOF]\n\r"); } break; } /* check if there is an eof character in input */ for (i = 0; i < len && buf[i] != tty_eof; i++); if (buf[i] == tty_eof) { fprintf(stderr, "[Quit]\n\r"); break; } } if (len) { #ifdef DEBUG if(write(1, buf, len)); #endif if (write_all(wfd, buf, len) != len) { fprintf(stderr, "Error in writing to FIFO.\n"); close(rfd); close(wfd); break; } STATUS("\" OK\r\n"); } /* * Read from FIFO, write to terminal. */ if (FD_ISSET(rfd, &readfds)) { STATUS("FIFO read: "); len = read(rfd, buf, BUFSIZ); if (len < 0 && errno == EAGAIN) { /* * No data this time, but the writing end of the FIFO is still open. * Do nothing. */ ; } else if (len <= 0) { /* * Either an error or end of file. In either case, break out * of the loop. */ close(rfd); close(wfd); if (len < 0) { fprintf(stderr, "Error in reading from FIFO.\n"); } else fprintf(stderr, "[End]\n\r"); break; } else { if (!got_some) { if ((len=version_handshake(buf,len,wfd)) < 0) { close(rfd); close(wfd); break; } if (protocol_ver >= 1) { /* Tell run_erl size of terminal window */ signal(SIGWINCH, handle_sigwinch); raise(SIGWINCH); } got_some = 1; } /* * We successfully read at least one character. Write what we got. */ STATUS("Terminal write: \""); if (write_all(1, buf, len) != len) { fprintf(stderr, "Error in writing to terminal.\n"); close(rfd); close(wfd); break; } STATUS("\" OK\r\n"); } } } /* * Reset terminal characterstics * XXX */ tcsetattr(0, TCSANOW, &tty_rmode); return 0; }
int to_erl(int argc, char **argv) { char FIFO1[FILENAME_MAX], FIFO2[FILENAME_MAX]; int i, len, wfd, rfd; char pipename[FILENAME_MAX]; int pipeIx = 1; int force_lock = 0; int got_some = 0; #ifdef __OSE__ struct aiocb stdin_read_req, pipe_read_req; FmHandle stdin_fh, pipe_fh; char *stdin_buf, *pipe_buf; char *buf; union SIGNAL *sig; #else /* __UNIX__ */ char buf[BUFSIZ]; fd_set readfds; #endif if (argc >= 2 && argv[1][0]=='-') { switch (argv[1][1]) { case 'h': usage(argv[0]); exit(1); case 'F': force_lock = 1; break; default: fprintf(stderr,"Invalid option '%s'\n",argv[1]); exit(1); } pipeIx = 2; } #ifdef DEBUG fprintf(stderr, "%s: pid is : %d\n", argv[0],(int) #ifdef __OSE__ current_process() #else /* __UNIX__ */ getpid() #endif ); #endif strn_cpy(pipename, sizeof(pipename), (argv[pipeIx] ? argv[pipeIx] : PIPE_DIR)); if(*pipename && pipename[strlen(pipename)-1] == '/') { /* The user wishes us to find a pipe name in the specified */ /* directory */ int highest_pipe_num = 0; DIR *dirp; struct dirent *direntp; dirp = opendir(pipename); if(!dirp) { fprintf(stderr, "Can't access pipe directory %s: %s\n", pipename, strerror(errno)); exit(1); } /* Check the directory for existing pipes */ while((direntp=readdir(dirp)) != NULL) { if(strncmp(direntp->d_name,PIPE_STUBNAME,PIPE_STUBLEN)==0) { int num = atoi(direntp->d_name+PIPE_STUBLEN+1); if(num > highest_pipe_num) highest_pipe_num = num; } } closedir(dirp); strn_catf(pipename, sizeof(pipename), (highest_pipe_num?"%s.%d":"%s"), PIPE_STUBNAME, highest_pipe_num); } /* if */ /* read FIFO */ sn_printf(FIFO1,sizeof(FIFO1),"%s.r",pipename); /* write FIFO */ sn_printf(FIFO2,sizeof(FIFO2),"%s.w",pipename); #ifndef __OSE__ /* Check that nobody is running to_erl on this pipe already */ if ((wfd = open (FIFO1, O_WRONLY|DONT_BLOCK_PLEASE, 0)) >= 0) { /* Open as server succeeded -- to_erl is already running! */ close(wfd); fprintf(stderr, "Another to_erl process already attached to pipe " "%s.\n", pipename); if (force_lock) { fprintf(stderr, "But we proceed anyway by force (-F).\n"); } else { exit(1); } } #endif if ((rfd = open (FIFO1, O_RDONLY|DONT_BLOCK_PLEASE, 0)) < 0) { #ifdef DEBUG fprintf(stderr, "Could not open FIFO %s for reading.\n", FIFO1); #endif fprintf(stderr, "No running Erlang on pipe %s: %s\n", pipename, strerror(errno)); exit(1); } #ifdef DEBUG fprintf(stderr, "to_erl: %s opened for reading\n", FIFO1); #endif if ((wfd = open (FIFO2, O_WRONLY|DONT_BLOCK_PLEASE, 0)) < 0) { #ifdef DEBUG fprintf(stderr, "Could not open FIFO %s for writing.\n", FIFO2); #endif fprintf(stderr, "No running Erlang on pipe %s: %s\n", pipename, strerror(errno)); close(rfd); exit(1); } #ifdef DEBUG fprintf(stderr, "to_erl: %s opened for writing\n", FIFO2); #endif #ifndef __OSE__ fprintf(stderr, "Attaching to %s (^D to exit)\n\n", pipename); #else fprintf(stderr, "Attaching to %s (^C to exit)\n\n", pipename); #endif #ifndef __OSE__ /* Set break handler to our handler */ signal(SIGINT,handle_ctrlc); /* * Save the current state of the terminal, and set raw mode. */ if (tcgetattr(0, &tty_rmode) , 0) { fprintf(stderr, "Cannot get terminals current mode\n"); exit(-1); } tty_smode = tty_rmode; tty_eof = '\004'; /* Ctrl+D to exit */ #ifdef DEBUG show_terminal_settings(&tty_rmode); #endif tty_smode.c_iflag = 1*BRKINT |/*Signal interrupt on break.*/ 1*IGNPAR |/*Ignore characters with parity errors.*/ 1*ISTRIP |/*Strip character.*/ 0; #if 0 0*IGNBRK |/*Ignore break condition.*/ 0*PARMRK |/*Mark parity errors.*/ 0*INPCK |/*Enable input parity check.*/ 0*INLCR |/*Map NL to CR on input.*/ 0*IGNCR |/*Ignore CR.*/ 0*ICRNL |/*Map CR to NL on input.*/ 0*IUCLC |/*Map upper-case to lower-case on input.*/ 0*IXON |/*Enable start/stop output control.*/ 0*IXANY |/*Enable any character to restart output.*/ 0*IXOFF |/*Enable start/stop input control.*/ 0*IMAXBEL|/*Echo BEL on input line too long.*/ #endif tty_smode.c_oflag = 1*OPOST |/*Post-process output.*/ 1*ONLCR |/*Map NL to CR-NL on output.*/ #ifdef XTABS 1*XTABS |/*Expand tabs to spaces. (Linux)*/ #endif #ifdef OXTABS 1*OXTABS |/*Expand tabs to spaces. (FreeBSD)*/ #endif #ifdef NL0 1*NL0 |/*Select newline delays*/ #endif #ifdef CR0 1*CR0 |/*Select carriage-return delays*/ #endif #ifdef TAB0 1*TAB0 |/*Select horizontal tab delays*/ #endif #ifdef BS0 1*BS0 |/*Select backspace delays*/ #endif #ifdef VT0 1*VT0 |/*Select vertical tab delays*/ #endif #ifdef FF0 1*FF0 |/*Select form feed delays*/ #endif 0; #if 0 0*OLCUC |/*Map lower case to upper on output.*/ 0*OCRNL |/*Map CR to NL on output.*/ 0*ONOCR |/*No CR output at column 0.*/ 0*ONLRET |/*NL performs CR function.*/ 0*OFILL |/*Use fill characters for delay.*/ 0*OFDEL |/*Fill is DEL, else NULL.*/ 0*NL1 | 0*CR1 | 0*CR2 | 0*CR3 | 0*TAB1 | 0*TAB2 | 0*TAB3 |/*Expand tabs to spaces.*/ 0*BS1 | 0*VT1 | 0*FF1 | #endif /* JALI: removed setting the tty_smode.c_cflag flags, since this is not */ /* advisable if this is a *real* terminal, such as the console. In fact */ /* this may hang the entire machine, deep, deep down (signalling break */ /* or toggling the abort switch doesn't help) */ tty_smode.c_lflag = 0; #if 0 0*ISIG |/*Enable signals.*/ 0*ICANON |/*Canonical input (erase and kill processing).*/ 0*XCASE |/*Canonical upper/lower presentation.*/ 0*ECHO |/*Enable echo.*/ 0*ECHOE |/*Echo erase character as BS-SP-BS.*/ 0*ECHOK |/*Echo NL after kill character.*/ 0*ECHONL |/*Echo NL.*/ 0*NOFLSH |/*Disable flush after interrupt or quit.*/ 0*TOSTOP |/*Send SIGTTOU for background output.*/ 0*ECHOCTL|/*Echo control characters as ^char, delete as ^?.*/ 0*ECHOPRT|/*Echo erase character as character erased.*/ 0*ECHOKE |/*BS-SP-BS erase entire line on line kill.*/ 0*FLUSHO |/*Output is being flushed.*/ 0*PENDIN |/*Retype pending input at next read or input character.*/ 0*IEXTEN |/*Enable extended (implementation-defined) functions.*/ #endif tty_smode.c_cc[VMIN] =0;/* Note that VMIN is the same as VEOF! */ tty_smode.c_cc[VTIME] =0;/* Note that VTIME is the same as VEOL! */ tty_smode.c_cc[VINTR] =3; tcsetattr(0, TCSADRAIN, &tty_smode); #ifdef DEBUG show_terminal_settings(&tty_smode); #endif #endif /* !__OSE__ */ /* * "Write a ^L to the FIFO which causes the other end to redisplay * the input line." * This does not seem to work as was intended in old comment above. * However, this control character is now (R12B-3) used by run_erl * to trigger the version handshaking between to_erl and run_erl * at the start of every new to_erl-session. */ if (write(wfd, "\014", 1) < 0) { fprintf(stderr, "Error in writing ^L to FIFO.\n"); } #ifdef __OSE__ /* we have a tiny stack so we malloc the buffers */ stdin_buf = malloc(sizeof(char) * BUFSIZ); pipe_buf = malloc(sizeof(char) * BUFSIZ); efs_examine_fd(rfd,FLIB_FD_HANDLE,&pipe_fh); efs_examine_fd(0,FLIB_FD_HANDLE,&stdin_fh); READ_AIO(stdin_read_req,0,BUFSIZ,stdin_buf); READ_AIO(pipe_read_req,rfd,BUFSIZ,pipe_buf); #endif /* * read and write */ while (1) { #ifndef __OSE__ FD_ZERO(&readfds); FD_SET(0, &readfds); FD_SET(rfd, &readfds); if (select(rfd + 1, &readfds, NULL, NULL, NULL) < 0) { if (recv_sig) { FD_ZERO(&readfds); } else { fprintf(stderr, "Error in select.\n"); break; } } len = 0; /* * Read from terminal and write to FIFO */ if (recv_sig) { switch (recv_sig) { case SIGINT: fprintf(stderr, "[Break]\n\r"); buf[0] = '\003'; len = 1; break; case SIGWINCH: len = window_size_seq(buf,sizeof(buf)); break; default: fprintf(stderr,"Unexpected signal: %u\n",recv_sig); } recv_sig = 0; } else #else /* __OSE__ */ SIGSELECT sigsel[] = {0}; sig = receive(sigsel); len = 0; #endif #ifndef __OSE__ if (FD_ISSET(0,&readfds)) { len = read(0, buf, sizeof(buf)); #else /* __OSE__ */ if (sig->signo == FM_READ_PTR_REPLY && sig->fm_read_ptr.handle == stdin_fh) { len = sig->fm_read_ptr.status == EFS_SUCCESS ? sig->fm_read_ptr.actual : -1; buf = sig->fm_read_ptr.buffer; #endif if (len <= 0) { close(rfd); close(wfd); if (len < 0) { fprintf(stderr, "Error in reading from stdin.\n"); } else { fprintf(stderr, "[EOF]\n\r"); } break; } /* check if there is an eof character in input */ for (i = 0; i < len-1 && buf[i] != tty_eof; i++); if (buf[i] == tty_eof) { fprintf(stderr, "[Quit]\n\r"); break; } } if (len) { #ifdef DEBUG if(write(1, buf, len)); #endif if (write_all(wfd, buf, len) != len) { fprintf(stderr, "Error in writing to FIFO.\n"); close(rfd); close(wfd); break; } STATUS("\" OK\r\n"); #ifdef __OSE__ aio_dispatch(sig); READ_AIO(stdin_read_req, 0, BUFSIZ, stdin_buf); #endif } /* * Read from FIFO, write to terminal. */ #ifndef __OSE__ if (FD_ISSET(rfd, &readfds)) { STATUS("FIFO read: "); len = read(rfd, buf, BUFSIZ); #else /* __OSE__ */ if (sig->signo == FM_READ_PTR_REPLY && sig->fm_read_ptr.handle == pipe_fh) { len = sig->fm_read_ptr.status == EFS_SUCCESS ? sig->fm_read_ptr.actual : -1; buf = sig->fm_read_ptr.buffer; #endif if (len < 0 && errno == EAGAIN) { /* * No data this time, but the writing end of the FIFO is still open. * Do nothing. */ ; } else if (len <= 0) { /* * Either an error or end of file. In either case, break out * of the loop. */ close(rfd); close(wfd); if (len < 0) { fprintf(stderr, "Error in reading from FIFO.\n"); } else fprintf(stderr, "[End]\n\r"); break; } else { if (!got_some) { if ((len=version_handshake(buf,len,wfd)) < 0) { close(rfd); close(wfd); break; } #ifndef __OSE__ if (protocol_ver >= 1) { /* Tell run_erl size of terminal window */ signal(SIGWINCH, handle_sigwinch); raise(SIGWINCH); } #endif got_some = 1; } /* * We successfully read at least one character. Write what we got. */ STATUS("Terminal write: \""); if (write_all(1, buf, len) != len) { fprintf(stderr, "Error in writing to terminal.\n"); close(rfd); close(wfd); break; } STATUS("\" OK\r\n"); #ifdef __OSE__ aio_dispatch(sig); READ_AIO(pipe_read_req, rfd, BUFSIZ, pipe_buf); #endif } } } #ifndef __OSE__ /* * Reset terminal characterstics * XXX */ tcsetattr(0, TCSADRAIN, &tty_rmode); #endif return 0; } /* Call write() until entire buffer has been written or error. * Return len or -1. */ static int write_all(int fd, const char* buf, int len) { int left = len; int written; while (left) { written = write(fd,buf,left); if (written < 0) { return -1; } left -= written; buf += written; } return len; } #ifndef __OSE__ static int window_size_seq(char* buf, size_t bufsz) { #ifdef TIOCGWINSZ struct winsize ws; static const char prefix[] = "\033_"; static const char suffix[] = "\033\\"; /* This Esc sequence is called "Application Program Command" and seems suitable to use for our own customized stuff. */ if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == 0) { int len = sn_printf(buf, bufsz, "%swinsize=%u,%u%s", prefix, ws.ws_col, ws.ws_row, suffix); return len; } #endif /* TIOCGWINSZ */ return 0; } #endif /* !__OSE__ */ /* to_erl run_erl * | | * |---------- '\014' -------->| (session start) * | | * |<---- "[run_erl v1-0]" ----| (version interval) * | | * |--- Esc_"version=1"Esc\ -->| (common version) * | | */ static int version_handshake(char* buf, int len, int wfd) { unsigned re_high=0, re_low; char *end = find_str(buf,len,"]\n"); if (end && sscanf(buf,"[run_erl v%u-%u",&re_high,&re_low)==2) { char wbuf[30]; int wlen; if (re_low > RUN_ERL_HI_VER || re_high < RUN_ERL_LO_VER) { fprintf(stderr,"Incompatible versions: to_erl=v%u-%u run_erl=v%u-%u\n", RUN_ERL_HI_VER, RUN_ERL_LO_VER, re_high, re_low); return -1; } /* Choose highest common version */ protocol_ver = re_high < RUN_ERL_HI_VER ? re_high : RUN_ERL_HI_VER; wlen = sn_printf(wbuf, sizeof(wbuf), "\033_version=%u\033\\", protocol_ver); if (write_all(wfd, wbuf, wlen) < 0) { fprintf(stderr,"Failed to send version handshake\n"); return -1; } end += 2; len -= (end-buf); memmove(buf,end,len); } else { /* we assume old run_erl without version handshake */ protocol_ver = 0; } if (re_high != RUN_ERL_HI_VER) { fprintf(stderr,"run_erl has different version, " "using common protocol level %u\n", protocol_ver); } return len; }