summaryrefslogtreecommitdiff
path: root/ptyim.c
diff options
context:
space:
mode:
Diffstat (limited to 'ptyim.c')
-rw-r--r--ptyim.c132
1 files changed, 79 insertions, 53 deletions
diff --git a/ptyim.c b/ptyim.c
index 35f5563..caa0f0f 100644
--- a/ptyim.c
+++ b/ptyim.c
@@ -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;
}