rawtty

run program under raw tty
git clone https://logand.com/git/rawtty.git/
Log | Files | Refs

commit 323c6ecd3e909d81832443f44729507ad1f5d9a2
Author: Tomas Hlavaty <tom@logand.com>
Date:   Fri, 15 Feb 2013 20:22:49 +0100

initial commit

Diffstat:
A.gitignore | 3+++
AMakefile | 10++++++++++
Arawtty.c | 147+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Arawttytestchild.c | 40++++++++++++++++++++++++++++++++++++++++
4 files changed, 200 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1,3 @@ +rawtty +rawttytestchild +*~ diff --git a/Makefile b/Makefile @@ -0,0 +1,10 @@ +all: rawtty rawttytestchild + +rawtty: rawtty.c + $(CC) -o $@ $@.c + +rawttytestchild: rawttytestchild.c + $(CC) -o $@ $@.c + +clean: + rm -f rawtty rawttytestchild diff --git a/rawtty.c b/rawtty.c @@ -0,0 +1,147 @@ +/* + + rawtty -- run program under raw tty + + Copyright (C) 2013 Tomas Hlavaty <tom at logand.com> + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +*/ + +#include <termios.h> +#include <unistd.h> +#include <stdlib.h> +#include <fcntl.h> +#include <errno.h> +//#include <stdio.h> + +#define BLEN 1024 + +static int childpipe[2]; + +static struct termios old; +static int selfpipe[2]; + +static int die(char *msg) { + write(STDERR_FILENO, "error: ", 7); + write(STDERR_FILENO, msg, strlen(msg)); + write(STDERR_FILENO, "\n", 1); + exit(1); + return 1; +} + +static void cleanup(void) { + tcsetattr(STDIN_FILENO, TCSAFLUSH, &old); +} + +static void setup(void) { + isatty(STDIN_FILENO) || die("not on a tty"); + tcgetattr(STDIN_FILENO, &old) < 0 && die("can't query tty"); + atexit(cleanup) && die("can't clean up"); + struct termios raw = old; + raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); + raw.c_oflag &= ~(OPOST); + raw.c_cflag |= (CS8); + raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); + raw.c_cc[VMIN] = 0; + raw.c_cc[VTIME] = 0; + tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw) < 0 && die("can't set raw mode"); +} + +static void handler(int signo) { + unsigned char n = signo; + write(selfpipe[1], &n, 1); + //fprintf(stderr, "handler %d\n", signo); +} + +static void nonblocking(int fd) { + int x = fcntl(fd, F_GETFL); + x < 0 && die("F_GETFL"); + fcntl(fd, F_SETFL, x | O_NONBLOCK) < 0 && die("O_NONBLOCK"); +} + +static void parent() { + close(childpipe[0]) == -1 && die("parent can't close read end"); + dup2(childpipe[1], STDOUT_FILENO); + close(childpipe[1]) == -1 && die("parent can't close write end"); + nonblocking(STDOUT_FILENO); + pipe(selfpipe) == -1 && die("can't create self pipe"); + nonblocking(selfpipe[0]); + nonblocking(selfpipe[1]); + signal(SIGCHLD, handler); + fd_set rfds; + fd_set wfds; + char buf[BLEN]; + int abuf = 0, zbuf = 0; + for(;;) { + FD_ZERO(&rfds); + FD_ZERO(&wfds); + if(0 < zbuf) FD_SET(STDOUT_FILENO, &wfds); + else FD_SET(STDIN_FILENO, &rfds); + FD_SET(selfpipe[0], &rfds); + switch(select(FD_SETSIZE, &rfds, &wfds, NULL, NULL)) { + case -1: EINTR == errno || die("can't select"); break; + case 0: die("no data"); + default: + if(FD_ISSET(STDIN_FILENO, &rfds)) { + zbuf = read(STDIN_FILENO, buf, BLEN); + zbuf < 1 && die("can't read"); + //if(4 == *buf) die("^d"); + //if(3 == *buf) die("^c"); + } + else if(FD_ISSET(STDOUT_FILENO, &wfds)) { + int n = write(STDOUT_FILENO, buf, zbuf - abuf); + n < 1 && die("can't write"); + abuf += n; + if(zbuf <= abuf) abuf = zbuf = 0; + } + else if(FD_ISSET(selfpipe[0], &rfds)) { + unsigned char n; + while(0 < read(selfpipe[0], &n, 1)); + //fprintf(stderr, "sig %d \n", (int) n); + exit(0); + } + else die("unhandled select case"); + } + } + //int stat; + //wait(&stat); +} + +static void child(char *argv[]) { + close(childpipe[1]) == -1 && die("child can't close write end"); + dup2(childpipe[0], STDIN_FILENO); + close(childpipe[0]) == -1 && die("child can't close read end"); + execvp(argv[1], &argv[1]); + die("can't execute"); +} + +int main(int argc, char *argv[]) { + 0 < argc || die("usage: rawtty program [arg...]"); + setup(); + pipe(childpipe) == -1 && die("can't create child pipe"); + switch(fork()) { + case -1: die("can't fork"); + case 0: child(argv); + default: parent(); + } + return 0; +} diff --git a/rawttytestchild.c b/rawttytestchild.c @@ -0,0 +1,40 @@ +/* + + rawttytestchild -- test program to be run with rawtty + + Copyright (C) 2013 Tomas Hlavaty <tom at logand.com> + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation files + (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +*/ + +#include <unistd.h> +#include <stdlib.h> + +int main() { + unsigned char c; + while(0 < read(STDIN_FILENO, &c, 1)) { + if(c < 'a' || 'z' < c) break; + c += 'A' - 'a'; + write(STDOUT_FILENO, &c, 1); + } + return 0; +}