#include #include #include #include #include #include #include #include #ifdef DEBUG_MESSAGE #define DEBUG(_s, ...) fprintf(stderr, _s, ## __VA_ARGS__) #else #define DEBUG(_s, ...) #endif #define elt0(_exp) ((_exp) < 0) #define check(_x, _cond, ...) do { if (_cond(_x)) { fatal_error(__VA_ARGS__); } } while (0) #define fatal_error(...) do { fprintf(stderr, __VA_ARGS__); exit(1); } while (0) #define GECKO_BAUD B115200 static int setup_term(const char *name) { int fd; int flags; struct termios tio; #define O(_ex, _m) check(_ex, elt0, "error " _m " %s: %s\n", name, strerror(errno)) O(fd = openat(AT_FDCWD, name, O_RDWR | O_NOCTTY), "opening"); O(tcgetattr(fd, &tio), "getting tio attrs for"); O(cfsetispeed(&tio, GECKO_BAUD), "setting ispeed of"); O(cfsetospeed(&tio, GECKO_BAUD), "setting ospeed of"); tio.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON); tio.c_oflag &= ~OPOST; tio.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); tio.c_cflag &= ~(CSIZE | PARENB); tio.c_cflag |= CS8; O(tcsetattr(fd, TCSANOW, &tio), "setting tio attrs for"); O(flags = fcntl(fd, F_GETFL), "getting stream status for"); flags |= O_NONBLOCK; O(fcntl(fd, F_SETFL, flags), "setting stream status for"); #undef O return fd; } static void handle_command(const char *cmd) { } int main(int argc, char **argv) { struct termios tio; int tfd; unsigned char buf[1024]; char cmdbuf[1024]; struct pollfd fds[2]; int infd; int flags; int can_write = 0; size_t partialcmd_sz = 0; int test_mode = 0; if (argc != 2) { fprintf(stderr, "Usage: %s \n", argv[0]); return 1; } tfd = setup_term(argv[1]); check(infd = dup(STDIN_FILENO), elt0, "error duplicating stdin: %s\n", strerror(errno)); check(flags = fcntl(infd, F_GETFL), elt0, "error getting stream status for stdin: %s\n", strerror(errno)); flags |= O_NONBLOCK; check(fcntl(infd, F_SETFL, flags), elt0, "setting stream status for stdin: %s\n", strerror(errno)); fds[0].fd = tfd; fds[0].events = POLLIN | POLLOUT; fds[1].fd = STDIN_FILENO; fds[1].events = POLLIN; while (1) { int nready; check(nready = poll(fds, 2, -1), elt0, "poll()ing: %s\n", strerror(errno)); if (nready == 0) continue; for (nfds_t i = 0; i < 2; ++i) { if (fds[i].revents & (POLLERR | POLLHUP)) { fatal_error("stream error or hangup condition on %d\n", fds[i].fd); } if (fds[i].revents & POLLIN) { ssize_t nread; while ((nread = read(fds[i].fd, buf, 1024)) > 0) { if (fds[i].fd == infd) { /* command */ for (ssize_t cidx = 0; cidx < nread; ++i) { /* TODO: split command by lines */ } } else { /* gecko */ } check(write(STDOUT_FILENO, buf, nread), elt0, "write(%d) failed: %s\n", STDOUT_FILENO, strerror(errno)); } if (nread == 0 && fds[i].fd == tfd) { fatal_error("EOF reached on terminal.\n"); } if (nread < 0 && errno != EAGAIN) { fatal_error("io error on fd %d: %s\n", fds[i].fd, strerror(errno)); } } if (fds[i].revents & POLLOUT) { fds[i].events &= ~POLLOUT; can_write = 1; } } } close(tfd); close(infd); return 0; }