diff options
Diffstat (limited to 'ptyim.c')
-rw-r--r-- | ptyim.c | 132 |
1 files changed, 79 insertions, 53 deletions
@@ -8,16 +8,23 @@ #include <unistd.h> #include <sys/ioctl.h> #include <termios.h> -//#include <asm/termbits.h> #include <string.h> #include <signal.h> #include "im.h" +#define WRITE_BUFFER_LEN 32 +//determines if the master process is running int running = 1; //hook for when the pty child process dies void childhook(int a) { running = 0; } +//pty master and slave fd int pty_slave = -1; +int pty_master = -1; +//freopen requires fn and not fd since its a unix function +char * pty_slave_fn; +//termios of stdin before we condition it, restored on process exit +struct termios stdin_termio_bk; //terminal rows and cols int trows = 0; int tcols = 0; @@ -34,33 +41,25 @@ void winchhook(int a) { ioctl(pty_slave, TIOCSWINSZ, &sz); } - -int main (int argc, char * argv[], char * envp[]) { +//return 0 on success, -1 on error +//sets the global vars pty_master and pty_slave +int make_pty() { //creates the pty master - int pty_master = posix_openpt(O_RDWR); + pty_master = posix_openpt(O_RDWR); if (pty_master < 0) { fprintf(stderr, "errno: %d, failed to create pty master", errno); return errno; } - //makes it nonblocking + //make the master pty nonblocking fcntl(pty_master, F_SETFL,O_NONBLOCK); - //make it raw - struct termios stdin_termio; - struct termios stdin_termio_bk; - tcgetattr(STDIN_FILENO,&stdin_termio); - tcgetattr(STDIN_FILENO,&stdin_termio_bk); - cfmakeraw(&stdin_termio); - tcsetattr(STDIN_FILENO,TCSANOW,&stdin_termio); - //make it nonblocking - fcntl(STDIN_FILENO, F_SETFL,O_NONBLOCK); - - + //unlock the slave pty if ( unlockpt(pty_master) <0) { fprintf(stderr, "errno: %d, failed to unlock pty slave", errno); return errno; } + //gets slave path - char * pty_slave_fn = ptsname(pty_master); + pty_slave_fn = ptsname(pty_master); //tries to open pty slave pty_slave = open(pty_slave_fn, O_RDWR); if (pty_slave < 0) { @@ -68,14 +67,40 @@ int main (int argc, char * argv[], char * envp[]) { errno, pty_slave_fn); return errno; } + //make the pty slave the same line discipline stdin was tcsetattr(pty_slave,TCSANOW,&stdin_termio_bk); - //syncs the window sizes for the first time + return 0; +} +//makes stdin raw and unblocking, previous state stored in global var +//stdin_termio_bk +void condition_stdin() { + struct termios stdin_termio; + //save existing termios settings + tcgetattr(STDIN_FILENO,&stdin_termio); + tcgetattr(STDIN_FILENO,&stdin_termio_bk); + //make it raw + cfmakeraw(&stdin_termio); + tcsetattr(STDIN_FILENO,TCSANOW,&stdin_termio); + //make it nonblocking + fcntl(STDIN_FILENO, F_SETFL,O_NONBLOCK); +} +void restore_stdin() { + tcsetattr(STDIN_FILENO,TCSANOW,&stdin_termio_bk); +} +int main (int argc, char * argv[], char * envp[]) { + condition_stdin(); + if (make_pty() != 0) { + restore_stdin(); + return errno; + } + //syncs the window sizes for the first time by manually running the + //resize interrupt handler winchhook(0); //forks for running bash pid_t mypid = fork(); if (mypid == 0) { - + //child process //set self to be session leader if (setsid() <0) { fprintf(stderr, "failed to make new session\n"); @@ -88,71 +113,72 @@ int main (int argc, char * argv[], char * envp[]) { if (ioctl(pty_slave, TIOCSCTTY, 0)) { fprintf(stderr, "errno: %d, failed to set controlling tty\n", errno); } - - - /* * Opens up the Shell now */ - - //opens up the slave pty - //needs to fork - //then set its own process group - //need to set the terminal - //exec bash then - //gets the shell to use, order is - // argument 1, then $SHELL< then /bin/sh + // First checks argument, then env, then default /bin/sh char * shellpath = "/bin/sh"; if (argc >1) { shellpath = argv[1]; } else if (getenv("SHELL") != NULL) { shellpath = getenv("SHELL"); } - //gets the terminal environmental variabke, 32 should be enough - char env_term[32] = "TERM="; - strcat(env_term, getenv("TERM")); - char env_home[32] = "HOME="; - strcat(env_home, getenv("HOME")); - char * shell_envs[3] = {env_term,env_home, NULL}; + //by convention we should set the first arg to the path to the + //shell, also should be null terminated char * shell_args[2] = {shellpath, NULL}; - //if (execve(shellpath,shell_args, shell_envs) == -1) { + //the process is now replaced with bash if (execve(shellpath,shell_args, envp) == -1) { fprintf(stderr, "errno: %d, Failed to start shell '%s'\n", errno, shellpath); return errno; } + //code should never reach this point since we ran execve //should automatically close any file descriptors _exit(0); } else { + //master process + //registers interrupts signal(SIGCHLD, childhook); signal(SIGWINCH, winchhook); - char readbuffer[1] = {0}; - int chars_read = 0; + //display the im for the first time + disp_im(STDIN_FILENO, trows, tcols); + + //1 char buffer for reading from stdin and writing to pty_master + char read_buffer[1] = {0}; + + //buffer for reading from pty_master and writing to stdout + char write_buffer[WRITE_BUFFER_LEN] = {0}; //open while (running) { - //just relay everything for now - //read uses file descriptors and is a system call - chars_read = read(pty_master,readbuffer,1); - if (chars_read >0) { - write(STDOUT_FILENO,readbuffer,1); + //only read/write syscalls work well for this, printfs + //etcs do not work + // pty_master -> STDOUT + int wchars_read = read(pty_master,write_buffer, WRITE_BUFFER_LEN); + if (wchars_read >0) { + write(STDOUT_FILENO,write_buffer,wchars_read); } - - chars_read = read(STDIN_FILENO, readbuffer, 1); - if (chars_read > 0) { - //write(pty_master,readbuffer,1); - //relays input from stdin - char input_buffer[IM_TABLE_ENTRY_LEN] = {0}; - int im_chars = update_im_state(readbuffer[0], + // stdin -> pty_master, im logic is also here + int rchars_read = read(STDIN_FILENO, read_buffer, 1); + if (rchars_read > 0) { + //feeds the input char into the im state machine + char input_buffer[IM_TABLE_ENTRY_LEN+1] = {0}; + int im_chars = update_im_state(read_buffer[0], input_buffer); + //just in case it wasn't null terminated right input_buffer[im_chars] = 0; if (im_chars >0) { + //writes the input into pty_master if + //there was an output from the state + //machine write(pty_master,input_buffer,im_chars); } + //any input update will lead to a disp_im update disp_im(STDIN_FILENO, trows, tcols); } } } + //exit, only the master process should reach this point close(pty_master); - tcsetattr(STDIN_FILENO,TCSANOW,&stdin_termio_bk); - //close(pty_slave); + close(pty_slave); + restore_stdin(); return 0; } |