commit 323c6ecd3e909d81832443f44729507ad1f5d9a2
Author: Tomas Hlavaty <tom@logand.com>
Date: Fri, 15 Feb 2013 20:22:49 +0100
initial commit
Diffstat:
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;
+}