int main(int argc, char **argv) { int childpid; int sfd = -1; int fd; char *p, *ptyslave=NULL; int i = 1; int off_argv; int calculated_pipename = 0; int highest_pipe_num = 0; program_name = argv[0]; if(argc<4) { usage(argv[0]); exit(1); } init_outbuf(); if (!strcmp(argv[1],"-daemon")) { daemon_init(); ++i; } off_argv = i; strn_cpy(pipename, sizeof(pipename), argv[i++]); strn_cpy(log_dir, sizeof(log_dir), argv[i]); strn_cpy(statusfile, sizeof(statusfile), log_dir); strn_cat(statusfile, sizeof(statusfile), STATUSFILENAME); #ifdef DEBUG status("%s: pid is : %d\n", argv[0], getpid()); #endif /* Get values for LOG file handling from the environment */ if ((p = getenv("RUN_ERL_LOG_ALIVE_MINUTES"))) { log_alive_minutes = atoi(p); if (!log_alive_minutes) { ERROR1(LOG_ERR,"Minimum value for RUN_ERL_LOG_ALIVE_MINUTES is 1 " "(current value is %s)",p); } log_activity_minutes = log_alive_minutes / 3; if (!log_activity_minutes) { ++log_activity_minutes; } } if ((p = getenv("RUN_ERL_LOG_ACTIVITY_MINUTES"))) { log_activity_minutes = atoi(p); if (!log_activity_minutes) { ERROR1(LOG_ERR,"Minimum value for RUN_ERL_LOG_ACTIVITY_MINUTES is 1 " "(current value is %s)",p); } } if ((p = getenv("RUN_ERL_LOG_ALIVE_FORMAT"))) { if (strlen(p) > ALIVE_BUFFSIZ) { ERROR1(LOG_ERR, "RUN_ERL_LOG_ALIVE_FORMAT can contain a maximum of " "%d characters", ALIVE_BUFFSIZ); } strn_cpy(log_alive_format, sizeof(log_alive_format), p); } else { strn_cpy(log_alive_format, sizeof(log_alive_format), DEFAULT_LOG_ALIVE_FORMAT); } if ((p = getenv("RUN_ERL_LOG_ALIVE_IN_UTC")) && strcmp(p,"0")) { ++log_alive_in_gmt; } if ((p = getenv("RUN_ERL_LOG_GENERATIONS"))) { log_generations = atoi(p); if (log_generations < LOG_MIN_GENERATIONS) ERROR1(LOG_ERR,"Minimum RUN_ERL_LOG_GENERATIONS is %d", LOG_MIN_GENERATIONS); if (log_generations > LOG_MAX_GENERATIONS) ERROR1(LOG_ERR,"Maximum RUN_ERL_LOG_GENERATIONS is %d", LOG_MAX_GENERATIONS); } if ((p = getenv("RUN_ERL_LOG_MAXSIZE"))) { log_maxsize = atoi(p); if (log_maxsize < LOG_MIN_MAXSIZE) ERROR1(LOG_ERR,"Minimum RUN_ERL_LOG_MAXSIZE is %d", LOG_MIN_MAXSIZE); } /* * Create FIFOs and open them */ if(*pipename && pipename[strlen(pipename)-1] == '/') { /* The user wishes us to find a unique pipe name in the specified */ /* directory */ DIR *dirp; struct dirent *direntp; calculated_pipename = 1; dirp = opendir(pipename); if(!dirp) { ERRNO_ERR1(LOG_ERR,"Can't access pipe directory '%s'.", pipename); 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), "%s.%d", PIPE_STUBNAME, highest_pipe_num+1); } /* if */ for(;;) { /* write FIFO - is read FIFO for `to_erl' program */ strn_cpy(fifo1, sizeof(fifo1), pipename); strn_cat(fifo1, sizeof(fifo1), ".r"); if (create_fifo(fifo1, PERM) < 0) { ERRNO_ERR1(LOG_ERR,"Cannot create FIFO %s for writing.", fifo1); exit(1); } /* read FIFO - is write FIFO for `to_erl' program */ strn_cpy(fifo2, sizeof(fifo2), pipename); strn_cat(fifo2, sizeof(fifo2), ".w"); /* Check that nobody is running run_erl already */ if ((fd = sf_open(fifo2, O_WRONLY|DONT_BLOCK_PLEASE, 0)) >= 0) { /* Open as client succeeded -- run_erl is already running! */ sf_close(fd); if (calculated_pipename) { ++highest_pipe_num; strn_catf(pipename, sizeof(pipename), "%s.%d", PIPE_STUBNAME, highest_pipe_num+1); continue; } fprintf(stderr, "Erlang already running on pipe %s.\n", pipename); exit(1); } if (create_fifo(fifo2, PERM) < 0) { ERRNO_ERR1(LOG_ERR,"Cannot create FIFO %s for reading.", fifo2); exit(1); } break; } /* * Open master pseudo-terminal */ if ((mfd = open_pty_master(&ptyslave, &sfd)) < 0) { ERRNO_ERR0(LOG_ERR,"Could not open pty master"); exit(1); } /* * Now create a child process */ if ((childpid = fork()) < 0) { ERRNO_ERR0(LOG_ERR,"Cannot fork"); exit(1); } if (childpid == 0) { /* Child */ sf_close(mfd); /* disassociate from control terminal */ #ifdef USE_SETPGRP_NOARGS /* SysV */ setpgrp(); #elif defined(USE_SETPGRP) /* BSD */ setpgrp(0,getpid()); #else /* POSIX */ setsid(); #endif /* Open the slave pty */ if (sfd < 0) { /* not allocated by open_pty_master */ if ((sfd = open_pty_slave(ptyslave)) < 0) { ERRNO_ERR1(LOG_ERR,"Could not open pty slave '%s'", ptyslave); exit(1); } /* But sfd may be one of the stdio fd's now, and we should be unmodern and not use dup2... */ /* easiest to dup it up... */ while (sfd < 3) { sfd = dup(sfd); } } #if defined(HAVE_OPENPTY) && defined(TIOCSCTTY) else { /* sfd is from open_pty_master * openpty -> fork -> login_tty (forkpty) * * It would be preferable to implement a portable * forkpty instead of open_pty_master / open_pty_slave */ /* login_tty(sfd); <- FAIL */ ioctl(sfd, TIOCSCTTY, (char *)NULL); } #endif #ifndef NO_SYSLOG /* Before fiddling with file descriptors we make sure syslog is turned off or "closed". In the single case where we might want it again, we will open it again instead. Would not want syslog to go to some other fd... */ if (run_daemon) { closelog(); } #endif /* Close stdio */ sf_close(0); sf_close(1); sf_close(2); if (dup(sfd) != 0 || dup(sfd) != 1 || dup(sfd) != 2) { status("Cannot dup\n"); } sf_close(sfd); exec_shell(argv+off_argv); /* exec_shell expects argv[2] to be */ /* the command name, so we have to */ /* adjust. */ } else { /* Parent */ /* Ignore the SIGPIPE signal, write() will return errno=EPIPE */ struct sigaction sig_act; sigemptyset(&sig_act.sa_mask); sig_act.sa_flags = 0; sig_act.sa_handler = SIG_IGN; sigaction(SIGPIPE, &sig_act, (struct sigaction *)NULL); sigemptyset(&sig_act.sa_mask); sig_act.sa_flags = SA_NOCLDSTOP; sig_act.sa_handler = catch_sigchild; sigaction(SIGCHLD, &sig_act, (struct sigaction *)NULL); /* * read and write: enter the workloop */ pass_on(childpid); } return 0; } /* main() */
/* * w- and r_pipename have to be pre-allocated of atleast FILENAME_MAX size */ int erts_run_erl_open_fifo(char *pipename,char *w_pipename,char *r_pipename) { int calculated_pipename = 0; int highest_pipe_num = 0; int fd; /* * Create FIFOs and open them */ if(*pipename && pipename[strlen(pipename)-1] == '/') { /* The user wishes us to find a unique pipe name in the specified */ /* directory */ DIR *dirp; struct dirent *direntp; calculated_pipename = 1; dirp = opendir(pipename); if(!dirp) { ERRNO_ERR1(LOG_ERR,"Can't access pipe directory '%s'.", pipename); return 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, BUFSIZ, "%s.%d", PIPE_STUBNAME, highest_pipe_num+1); } /* if */ for(;;) { /* write FIFO - is read FIFO for `to_erl' program */ strn_cpy(w_pipename, BUFSIZ, pipename); strn_cat(w_pipename, BUFSIZ, ".r"); if (create_fifo(w_pipename, PERM) < 0) { ERRNO_ERR1(LOG_ERR,"Cannot create FIFO %s for writing.", w_pipename); return 1; } /* read FIFO - is write FIFO for `to_erl' program */ strn_cpy(r_pipename, BUFSIZ, pipename); strn_cat(r_pipename, BUFSIZ, ".w"); /* Check that nobody is running run_erl already */ if ((fd = sf_open(r_pipename, O_WRONLY|DONT_BLOCK_PLEASE, 0)) >= 0) { /* Open as client succeeded -- run_erl is already running! */ sf_close(fd); if (calculated_pipename) { ++highest_pipe_num; strn_catf(pipename, BUFSIZ, "%s.%d", PIPE_STUBNAME, highest_pipe_num+1); continue; } ERROR1(LOG_ERR, "Erlang already running on pipe %s.\n", pipename); unlink(w_pipename); return 1; } if (create_fifo(r_pipename, PERM) < 0) { unlink(w_pipename); ERRNO_ERR1(LOG_ERR,"Cannot create FIFO %s for reading.", r_pipename); return 1; } break; } return 0; }
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; }